Position.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 #include "Position.hpp"
40 #include "WGS84Ellipsoid.hpp"
41 #include "GNSSconstants.hpp" // for TWO_PI, etc
42 #include "GNSSconstants.hpp" // for RAD_TO_DEG, etc
43 #include "MiscMath.hpp" // for RSS, SQRT
44 #include "Angle.hpp"
45 #include "DebugTrace.hpp"
46 
47 namespace gnsstk
48 {
49 
50  using namespace std;
51  using namespace StringUtils;
52 
53  // ----------- Part 1: coordinate systems --------------------------------
54  // Labels for coordinate systems supported by Position
55  static const char *SystemNames[] = {
56  "Unknown",
57  "Geodetic",
58  "Geocentric",
59  "Cartesian",
60  "Spherical"};
61 
62  // return string giving name of coordinate system
64  noexcept
65  { return SystemNames[system]; }
66 
67  // ----------- Part 2: tolerance -----------------------------------------
68  // One millimeter tolerance.
69  const double Position::ONE_MM_TOLERANCE = 0.001;
70  // One centimeter tolerance.
71  const double Position::ONE_CM_TOLERANCE = 0.01;
72  // One micron tolerance.
73  const double Position::ONE_UM_TOLERANCE = 0.000001;
74 
75  // Default tolerance for time equality in meters.
77 
78  // Sets the tolerance for output and comparisons, for this object only.
79  // See the constants in this file (e.g. ONE_MM_TOLERANCE)
80  // for some easy to use tolerance values.
81  // @param tol Tolerance in meters to be used by comparison operators.
82  Position& Position::setTolerance(const double tol)
83  noexcept
84  {
85  tolerance = tol;
86  return *this;
87  }
88 
89  // ----------- Part 3: member functions: constructors --------------------
90  //
91  // Default constructor.
93  noexcept
94  {
96  initialize(0.0,0.0,0.0,Unknown,&WGS84);
97  }
98 
99  Position::Position(const double& a,
100  const double& b,
101  const double& c,
103  const EllipsoidModel *ell,
104  const RefFrame& frame)
105  {
106  try {
107  initialize(a,b,c,s,ell,frame);
108  }
109  catch(GeometryException& ge) {
110  GNSSTK_RETHROW(ge);
111  }
112  }
113 
114  Position::Position(const double ABC[3],
116  const EllipsoidModel *ell,
117  const RefFrame& frame)
118  {
119  double a=ABC[0];
120  double b=ABC[1];
121  double c=ABC[2];
122  try {
123  initialize(a,b,c,s,ell,frame);
124  }
125  catch(GeometryException& ge) {
126  GNSSTK_RETHROW(ge);
127  }
128  }
129 
132  const EllipsoidModel *ell,
133  const RefFrame& frame)
134  {
135  double a=ABC[0];
136  double b=ABC[1];
137  double c=ABC[2];
138  try {
139  initialize(a,b,c,s,ell,frame);
140  }
141  catch(GeometryException& ge) {
142  }
143  }
144 
146  noexcept
147  {
148  double a=xvt.x[0];
149  double b=xvt.x[1];
150  double c=xvt.x[2];
151  initialize(a,b,c,Cartesian, NULL, xvt.frame);
152  }
153 
154  // ----------- Part 4: member functions: arithmetic ----------------------
155  //
157  noexcept
158  {
159  Position r(right);
160  CoordinateSystem savesys=system; // save the original system
161 
162  // convert to cartestian and difference there
163  transformTo(Cartesian);
164  r.transformTo(Cartesian);
165 
166  for(int i=0; i<3; i++)
167  theArray[i] -= r.theArray[i];
168 
169  transformTo(savesys); // transform back to the original system
170  return *this;
171  }
172 
174  noexcept
175  {
176  Position r(right);
177  CoordinateSystem savesys=system; // save the original system
178 
179  // convert to cartestian and difference there
180  transformTo(Cartesian);
181  r.transformTo(Cartesian);
182 
183  for(int i=0; i<3; i++)
184  theArray[i] += r.theArray[i];
185 
186  transformTo(savesys); // transform back to the original system
187  return *this;
188  }
189 
191  const Position& right)
192  noexcept
193  {
194  Position l(left),r(right);
195  // convert both to Cartesian
196  l.transformTo(Position::Cartesian);
198  // difference
199  l -= r;
200 
201  return l;
202  }
203 
205  const Position& right)
206  noexcept
207  {
208  Position l(left),r(right);
209  // convert both to Cartesian
210  l.transformTo(Position::Cartesian);
212  // add
213  l += r;
214 
215  return l;
216  }
217 
218  // ----------- Part 5: member functions: comparisons ---------------------
219  //
220  // Equality operator. Returns false if ell values differ.
221  bool Position::operator==(const Position &right) const
222  noexcept
223  {
224  if(AEarth != right.AEarth || eccSquared != right.eccSquared)
225  return false;
226  if(right.getReferenceFrame() != refFrame)
227  return false; //Unknown frames are considered the same.
228  if(range(*this,right) < tolerance)
229  return true;
230  else
231  return false;
232  }
233 
234  // Inequality operator. Returns true if ell values differ.
235  bool Position::operator!=(const Position &right) const
236  noexcept
237  {
238  return !(operator==(right));
239  }
240 
241  // ----------- Part 6: member functions: coordinate transformations ------
242  //
243  // Transform coordinate system. Does nothing if sys already matches the
244  // current value of member CoordinateSystem 'system'.
245  // @param sys coordinate system into which *this is to be transformed.
246  // @return *this
248  noexcept
249  {
250  if(sys == Unknown || sys == system) return *this;
251 
252  // this copies geoid information and tolerance
253  Position target(*this);
254 
255  // transform target.theArray and set target.system
256  switch(system) {
257  case Unknown:
258  return *this;
259  case Geodetic:
260  // --------------- Geodetic to ... ------------------------
261  switch(sys) {
262  case Unknown: case Geodetic: return *this;
263  case Geocentric:
264  convertGeodeticToGeocentric(*this,target,AEarth,eccSquared);
265  target.system = Geocentric;
266  break;
267  case Cartesian:
268  convertGeodeticToCartesian(*this,target,AEarth,eccSquared);
269  target.system = Cartesian;
270  break;
271  case Spherical:
272  convertGeodeticToGeocentric(*this,target,AEarth,eccSquared);
273  target.theArray[0] = 90 - target.theArray[0]; // geocen -> sph
274  target.system = Spherical;
275  break;
276  }
277  break;
278  case Geocentric:
279  // --------------- Geocentric to ... ----------------------
280  switch(sys) {
281  case Unknown: case Geocentric: return *this;
282  case Geodetic:
283  convertGeocentricToGeodetic(*this,target,AEarth,eccSquared);
284  target.system = Geodetic;
285  break;
286  case Cartesian:
287  convertGeocentricToCartesian(*this,target);
288  target.system = Cartesian;
289  break;
290  case Spherical:
291  target.theArray[0] = 90 - target.theArray[0]; // geocen -> sph
292  target.system = Spherical;
293  break;
294  }
295  break;
296  case Cartesian:
297  // --------------- Cartesian to ... -----------------------
298  switch(sys) {
299  case Unknown: case Cartesian: return *this;
300  case Geodetic:
301  convertCartesianToGeodetic(*this,target,AEarth,eccSquared);
302  target.system = Geodetic;
303  break;
304  case Geocentric:
305  convertCartesianToGeocentric(*this,target);
306  target.system = Geocentric;
307  break;
308  case Spherical:
309  convertCartesianToSpherical(*this,target);
310  target.system = Spherical;
311  break;
312  }
313  break;
314  case Spherical:
315  // --------------- Spherical to ... -----------------------
316  switch(sys) {
317  case Unknown: case Spherical: return *this;
318  case Geodetic:
319  theArray[0] = 90 - theArray[0]; // sph -> geocen
320  convertGeocentricToGeodetic(*this,target,AEarth,eccSquared);
321  target.system = Geodetic;
322  break;
323  case Geocentric:
324  target.theArray[0] = 90 - target.theArray[0]; // sph -> geocen
325  target.system = Geocentric;
326  break;
327  case Cartesian:
328  convertSphericalToCartesian(*this,target);
329  target.system = Cartesian;
330  break;
331  }
332  break;
333  } // end switch(system)
334 
335  *this = target;
336  return *this;
337  }
338 
339  // ----------- Part 7: member functions: get -----------------------------
340  //
341  // These routines retrieve coordinate values in all coordinate systems.
342  // Note that calling these will transform the Position to another coordinate
343  // system if that is required.
344  //
345 
347  noexcept
348  {
349  return refFrame;
350  }
351 
352  // Get X coordinate (meters)
354  noexcept
355  {
356  if(system == Cartesian)
357  return theArray[0];
358  Position t(*this);
359  t.transformTo(Cartesian);
360  return t.theArray[0];
361  }
362 
363  // Get Y coordinate (meters)
365  noexcept
366  {
367  if(system == Cartesian)
368  return theArray[1];
369  Position t(*this);
370  t.transformTo(Cartesian);
371  return t.theArray[1];
372  }
373 
374  // Get Z coordinate (meters)
376  noexcept
377  {
378  if(system == Cartesian)
379  return theArray[2];
380  Position t(*this);
381  t.transformTo(Cartesian);
382  return t.theArray[2];
383  }
384 
385  // Get geodetic latitude (degrees North).
387  noexcept
388  {
389  if(system == Geodetic)
390  return theArray[0];
391  Position t(*this);
392  t.transformTo(Geodetic);
393  return t.theArray[0];
394  }
395 
396  // Get geocentric latitude (degrees North),
397  // equal to 90 degress - theta in regular spherical coordinates.
399  noexcept
400  {
401  if(system == Geocentric)
402  return theArray[0];
403  Position t(*this);
404  t.transformTo(Geocentric);
405  return t.theArray[0];
406  }
407 
408  // Get spherical coordinate theta in degrees
410  noexcept
411  {
412  if(system == Spherical)
413  return theArray[0];
414  Position t(*this);
415  t.transformTo(Spherical);
416  return t.theArray[0];
417  }
418 
419  // Get spherical coordinate phi in degrees
421  noexcept
422  {
423  if(system == Spherical)
424  return theArray[1];
425  Position t(*this);
426  t.transformTo(Spherical);
427  return t.theArray[1];
428  }
429 
430  // Get longitude (degrees East),
431  // equal to phi in regular spherical coordinates.
433  noexcept
434  {
435  if(system != Cartesian)
436  return theArray[1];
437  Position t(*this);
438  t.transformTo(Spherical);
439  return t.theArray[1];
440  }
441 
442  // Get radius or distance from the center of Earth (meters),
443  // Same as radius in spherical coordinates.
445  noexcept
446  {
447  if(system == Spherical || system == Geocentric)
448  return theArray[2];
449  Position t(*this);
450  t.transformTo(Spherical);
451  return t.theArray[2];
452  }
453 
454  // Get height above ellipsoid (meters) (Geodetic).
456  noexcept
457  {
458  if(system == Geodetic)
459  return theArray[2];
460  Position t(*this);
461  t.transformTo(Geodetic);
462  return t.theArray[2];
463  }
464 
465  // ----------- Part 8: member functions: set -----------------------------
466  //
468  noexcept
469  {
470  refFrame = frame;
471  }
472 
479  {
480  if(!ell)
481  {
482  GeometryException ge("Given EllipsoidModel pointer is NULL.");
483  GNSSTK_THROW(ge);
484  }
485  AEarth = ell->a();
486  eccSquared = ell->eccSquared();
487  }
488 
489  // Set the Position given geodetic coordinates, system is set to Geodetic.
490  // @param lat geodetic latitude in degrees North
491  // @param lon geodetic longitude in degrees East
492  // @param ht height above the ellipsoid in meters
493  // @return a reference to this object.
494  // @throw GeometryException on invalid input
495  Position& Position::setGeodetic(const double lat,
496  const double lon,
497  const double ht,
498  const EllipsoidModel *ell)
499  {
500  if(lat > 90 || lat < -90)
501  {
502  GeometryException ge("Invalid latitude in setGeodetic: "
503  + StringUtils::asString(lat));
504  GNSSTK_THROW(ge);
505  }
506  theArray[0] = lat;
507 
508  theArray[1] = lon;
509  if(theArray[1] < 0)
510  theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
511  else if(theArray[1] >= 360)
512  theArray[1] -= 360*(unsigned long)(theArray[1]/360);
513 
514  theArray[2] = ht;
515 
516  if(ell) {
517  AEarth = ell->a();
518  eccSquared = ell->eccSquared();
519  }
520  system = Geodetic;
521 
522  return *this;
523  }
524 
525  // Set the Position given geocentric coordinates, system is set to Geocentric
526  // @param lat geocentric latitude in degrees North
527  // @param lon geocentric longitude in degrees East
528  // @param rad radius from the Earth's center in meters
529  // @return a reference to this object.
530  // @throw GeometryException on invalid input
532  const double lon,
533  const double rad)
534  {
535  if(lat > 90 || lat < -90)
536  {
537  GeometryException ge("Invalid latitude in setGeocentric: "
538  + StringUtils::asString(lat));
539  GNSSTK_THROW(ge);
540  }
541  if(rad < 0)
542  {
543  GeometryException ge("Invalid radius in setGeocentric: "
544  + StringUtils::asString(rad));
545  GNSSTK_THROW(ge);
546  }
547  theArray[0] = lat;
548  theArray[1] = lon;
549  theArray[2] = rad;
550 
551  if(theArray[1] < 0)
552  theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
553  else if(theArray[1] >= 360)
554  theArray[1] -= 360*(unsigned long)(theArray[1]/360);
555  system = Geocentric;
556 
557  return *this;
558  }
559 
560  // Set the Position given spherical coordinates, system is set to Spherical
561  // @param theta angle from the Z-axis (degrees)
562  // @param phi angle from the X-axis in the XY plane (degrees)
563  // @param rad radius from the center in meters
564  // @return a reference to this object.
565  // @throw GeometryException on invalid input
566  Position& Position::setSpherical(const double theta,
567  const double phi,
568  const double rad)
569  {
570  if(theta < 0 || theta > 180)
571  {
572  GeometryException ge("Invalid theta in setSpherical: "
573  + StringUtils::asString(theta));
574  GNSSTK_THROW(ge);
575  }
576  if(rad < 0)
577  {
578  GeometryException ge("Invalid radius in setSpherical: "
579  + StringUtils::asString(rad));
580  GNSSTK_THROW(ge);
581  }
582 
583  theArray[0] = theta;
584  theArray[1] = phi;
585  theArray[2] = rad;
586 
587  if(theArray[1] < 0)
588  theArray[1] += 360*(1+(unsigned long)(theArray[1]/360));
589  else if(theArray[1] >= 360)
590  theArray[1] -= 360*(unsigned long)(theArray[1]/360);
591  system = Spherical;
592 
593  return *this;
594  }
595 
596  // Set the Position given ECEF coordinates, system is set to Cartesian.
597  // @param X ECEF X coordinate in meters.
598  // @param Y ECEF Y coordinate in meters.
599  // @param Z ECEF Z coordinate in meters.
600  // @return a reference to this object.
601  Position& Position::setECEF(const double X,
602  const double Y,
603  const double Z)
604  noexcept
605  {
606  theArray[0] = X;
607  theArray[1] = Y;
608  theArray[2] = Z;
609  system = Cartesian;
610  return *this;
611  }
612 
613  // ----------- Part 9: member functions: setToString, printf -------------
614  //
615  // setToString, similar to scanf, this function takes a string and a
616  // format describing string in order to define Position
617  // values. The parameters it can take are listed below and
618  // described above with the printf() function.
619  //
620  // The specification must be sufficient to define a Position.
621  // The following table lists combinations that give valid
622  // Positions. Anything more or other combinations will give
623  // unknown (read as: "bad") results so don't try it. Anything
624  // less will throw an exception.
625  //
626  // @code
627  // %X %Y %Z (cartesian or ECEF)
628  // %x %y %z (cartesian or ECEF)
629  // %a %l %r (geocentric)
630  // %A %L %h (geodetic)
631  // %t %p %r (spherical)
632  // @endcode
633  //
634  // So
635  // @code
636  // pos.setToString("123.4342,9328.1982,-128987.399", "%X,%Y,%Z");
637  // @endcode
638  //
639  // works but
640  //
641  // @code
642  // pos.setToString("123.4342,9328.1982", "%X,%Y");
643  // @endcode
644  // doesn't work (incomplete specification because it doesn't specify
645  // a Position).
646  //
647  // Whitespace is unimportant here, the function will handle it.
648  // The caller must ensure that that the extra characters in
649  // the format string (ie '.' ',') are in the same relative
650  // location as they are in the actual string, see the example above.
651  //
652  // @param str string from which to get the Position coordinates
653  // @param fmt format to use to parse \c str.
654  // @throw GeometryException if \c fmt is an incomplete or invalid specification
655  // @throw StringException if an error occurs manipulating the
656  // \c str or \c fmt strings.
657  // @return a reference to this object.
658  Position& Position::setToString(const std::string& str,
659  const std::string& fmt)
660  {
661  try {
662  // make an object to return (so we don't fiddle with *this
663  // until it's necessary)
664  Position toReturn;
665 
666  // flags indicated these defined
667  bool hX=false, hY=false, hZ=false;
668  bool hglat=false, hlon=false, hht=false;
669  bool hclat=false, hrad=false;
670  bool htheta=false, hphi=false;
671  // store input values
672  double x=0.0, y=0.0, z=0.0, glat=0.0, lon=0.0, ht=0.0, clat=0.0,
673  rad=0.0, theta=0.0, phi=0.0;
674  // copy format and input string to parse
675  string f = fmt;
676  string s = str;
677  stripLeading(s);
678  stripTrailing(f);
679 
680  // parse strings... As we process each part, it's removed from both
681  // strings so when we reach 0, we're done
682  while ( (s.size() > 0) && (f.size() > 0) )
683  {
684  // remove everything in f and s up to the first % in f
685  // (these parts of the strings must be identical or this will break
686  // after it tries to remove it!)
687  while ( (s.length() != 0) && (f.length() != 0) && (f[0] != '%') )
688  {
689  // remove that character now and other whitespace
690  s.erase(0,1);
691  f.erase(0,1);
692  stripLeading(s);
693  stripLeading(f);
694  }
695 
696  // check just in case we hit the end of either string...
697  if ( (s.length() == 0) || (f.length() == 0) )
698  break;
699 
700  // lose the '%' in f...
701  f.erase(0,1);
702 
703  // if the format string is like %03f, get '3' as the field
704  // length.
705  string::size_type fieldLength = string::npos;
706 
707  if (!isalpha(f[0]))
708  {
709  fieldLength = asInt(f);
710 
711  // remove everything else up to the next character
712  // (in "%03f", that would be 'f')
713  while ((!f.empty()) && (!isalpha(f[0])))
714  f.erase(0,1);
715  if (f.empty())
716  break;
717  }
718 
719  // finally, get the character that should end this field, if any
720  char delimiter = 0;
721  if (f.size() > 1)
722  {
723  if (f[1] != '%')
724  {
725  delimiter = f[1];
726 
727  if (fieldLength == string::npos)
728  fieldLength = s.find(delimiter,0);
729  }
730  // if the there is no delimiter character and the next field
731  // is another part of the time to parse, assume the length
732  // of this field is 1
733  else if (fieldLength == string::npos)
734  {
735  fieldLength = 1;
736  }
737  }
738 
739  // figure out the next string to be removed. if there is a field
740  // length, use that first
741  string toBeRemoved = s.substr(0, fieldLength);
742 
743  // based on char at f[0], we know what to do...
744  switch (f[0])
745  {
746  //%x X() (meters)
747  //%y Y() (meters)
748  //%z Z() (meters)
749  //%X X()/1000 (kilometers)
750  //%Y Y()/1000 (kilometers)
751  //%Z Z()/1000 (kilometers)
752  case 'X':
753  x = asDouble(toBeRemoved) * 1000;
754  hX = true;
755  break;
756  case 'x':
757  x = asDouble(toBeRemoved);
758  hX = true;
759  break;
760  case 'Y':
761  y = asDouble(toBeRemoved) * 1000;
762  hY = true;
763  break;
764  case 'y':
765  y = asDouble(toBeRemoved);
766  hY = true;
767  break;
768  case 'Z':
769  z = asDouble(toBeRemoved) * 1000;
770  hZ = true;
771  break;
772  case 'z':
773  z = asDouble(toBeRemoved);
774  hZ = true;
775  break;
776  //%A geodeticLatitude() (degrees North)
777  //%a geocentricLatitude() (degrees North)
778  case 'A':
779  glat = asDouble(toBeRemoved);
780  if(glat > 90. || glat < -90.) {
781  InvalidRequest f(
782  "Invalid geodetic latitude for setTostring: "
783  + toBeRemoved);
784  GNSSTK_THROW(f);
785  }
786  hglat = true;
787  break;
788  case 'a':
789  clat = asDouble(toBeRemoved);
790  if(clat > 90. || clat < -90.) {
791  InvalidRequest f(
792  "Invalid geocentric latitude for setTostring: "
793  + toBeRemoved);
794  GNSSTK_THROW(f);
795  }
796  hclat = true;
797  break;
798  //%L longitude() (degrees East)
799  //%l longitude() (degrees East)
800  //%w longitude() (degrees West)
801  //%W longitude() (degrees West)
802  case 'L':
803  case 'l':
804  lon = asDouble(toBeRemoved);
805  if(lon < 0)
806  lon += 360*(1+(unsigned long)(lon/360));
807  else if(lon >= 360)
808  lon -= 360*(unsigned long)(lon/360);
809  hlon = true;
810  break;
811  case 'w':
812  case 'W':
813  lon = 360.0 - asDouble(toBeRemoved);
814  if(lon < 0)
815  lon += 360*(1+(unsigned long)(lon/360));
816  else if(lon >= 360)
817  lon -= 360*(unsigned long)(lon/360);
818  hlon = true;
819  break;
820  //%t theta() (degrees)
821  //%T theta() (radians)
822  case 't':
823  theta = asDouble(toBeRemoved);
824  if(theta > 180. || theta < 0.) {
825  InvalidRequest f("Invalid theta for setTostring: "
826  + toBeRemoved);
827  GNSSTK_THROW(f);
828  }
829  htheta = true;
830  break;
831  case 'T':
832  theta = asDouble(toBeRemoved) * RAD_TO_DEG;
833  if(theta > 90. || theta < -90.) {
834  InvalidRequest f("Invalid theta for setTostring: "
835  + toBeRemoved);
836  GNSSTK_THROW(f);
837  }
838  htheta = true;
839  break;
840  //%p phi() (degrees)
841  //%P phi() (radians)
842  case 'p':
843  phi = asDouble(toBeRemoved);
844  if(phi < 0)
845  phi += 360*(1+(unsigned long)(phi/360));
846  else if(phi >= 360)
847  phi -= 360*(unsigned long)(phi/360);
848  hphi = true;
849  break;
850  case 'P':
851  phi = asDouble(toBeRemoved) * RAD_TO_DEG;
852  if(phi < 0)
853  phi += 360*(1+(unsigned long)(phi/360));
854  else if(phi >= 360)
855  phi -= 360*(unsigned long)(phi/360);
856  hphi = true;
857  break;
858  //%r radius() meters
859  //%R radius()/1000 kilometers
860  //%h height() meters
861  //%H height()/1000 kilometers
862  case 'r':
863  rad = asDouble(toBeRemoved);
864  if(rad < 0.0) {
865  InvalidRequest f("Invalid radius for setTostring: "
866  + toBeRemoved);
867  GNSSTK_THROW(f);
868  }
869  hrad = true;
870  break;
871  case 'R':
872  rad = asDouble(toBeRemoved) * 1000;
873  if(rad < 0.0) {
874  InvalidRequest f("Invalid radius for setTostring: "
875  + toBeRemoved);
876  GNSSTK_THROW(f);
877  }
878  hrad = true;
879  break;
880  case 'h':
881  ht = asDouble(toBeRemoved);
882  hht = true;
883  break;
884  case 'H':
885  ht = asDouble(toBeRemoved) * 1000;
886  hht = true;
887  break;
888  default: // do nothing
889  break;
890  }
891  // remove the part of s that we processed
892  stripLeading(s,toBeRemoved,1);
893 
894  // remove the character we processed from f
895  f.erase(0,1);
896 
897  // check for whitespace again...
898  stripLeading(f);
899  stripLeading(s);
900 
901  }
902 
903  if ( s.length() != 0 )
904  {
905  // throw an error - something didn't get processed in the strings
906  InvalidRequest fe(
907  "Processing error - parts of strings left unread - " + s);
908  GNSSTK_THROW(fe);
909  }
910 
911  if (f.length() != 0)
912  {
913  // throw an error - something didn't get processed in the strings
914  InvalidRequest fe(
915  "Processing error - parts of strings left unread - " + f);
916  GNSSTK_THROW(fe);
917  }
918 
919  // throw if the specification is incomplete
920  if ( !(hX && hY && hZ) && !(hglat && hlon && hht) &&
921  !(hclat && hlon && hrad) && !(htheta && hphi && hrad)) {
922  InvalidRequest fe("Incomplete specification for setToString");
923  GNSSTK_THROW(fe);
924  }
925 
926  // define the Position toReturn
927  if(hX && hY && hZ)
928  toReturn.setECEF(x,y,z);
929  else if(hglat && hlon && hht)
930  toReturn.setGeodetic(glat,lon,ht);
931  else if(hclat && hlon && hrad)
932  toReturn.setGeocentric(clat,lon,rad);
933  else if(htheta && hphi && hrad)
934  toReturn.setSpherical(theta,phi,rad);
935 
936  *this = toReturn;
937  return *this;
938  }
939  catch(gnsstk::Exception& exc)
940  {
941  GeometryException ge(exc);
942  ge.addText("Failed to convert string to Position");
943  GNSSTK_THROW(ge);
944  }
945  catch(std::exception& exc)
946  {
947  GeometryException ge(exc.what());
948  ge.addText("Failed to convert string to Position");
949  GNSSTK_THROW(ge);
950  }
951  }
952 
953  // Format this Position into a string.
954  //
955  // Generate and return a string containing formatted
956  // Position coordinates, formatted by the specification \c fmt.
957  //
958  // \li \%x X() (meters)
959  // \li \%y Y() (meters)
960  // \li \%z Z() (meters)
961  // \li \%X X()/1000 (kilometers)
962  // \li \%Y Y()/1000 (kilometers)
963  // \li \%Z Z()/1000 (kilometers)
964  // \li \%A geodeticLatitude() (degrees North)
965  // \li \%a geocentricLatitude() (degrees North)
966  // \li \%L longitude() (degrees East)
967  // \li \%l longitude() (degrees East)
968  // \li \%w longitude() (degrees West)
969  // \li \%W longitude() (degrees West)
970  // \li \%t theta() (degrees)
971  // \li \%T theta() (radians)
972  // \li \%p phi() (degrees)
973  // \li \%P phi() (radians)
974  // \li \%r radius() meters
975  // \li \%R radius()/1000 kilometers
976  // \li \%h height() meters
977  // \li \%H height()/1000 kilometers
978  //
979  // @param fmt format to use for this time.
980  // @return a string containing this Position in the
981  // representation specified by \c fmt.
982  std::string Position::printf(const char *fmt) const
983  {
984  string rv = fmt;
985  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?x"),
986  string("xf"), X());
987  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?y"),
988  string("yf"), Y());
989  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?z"),
990  string("zf"), Z());
991  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?X"),
992  string("Xf"), X()/1000);
993  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?Y"),
994  string("Yf"), Y()/1000);
995  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?Z"),
996  string("Zf"), Z()/1000);
997 
998  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?A"),
999  string("Af"), geodeticLatitude());
1000  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?a"),
1001  string("af"), geocentricLatitude());
1002  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?L"),
1003  string("Lf"), longitude());
1004  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?l"),
1005  string("lf"), longitude());
1006  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?w"),
1007  string("wf"), 360-longitude());
1008  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?W"),
1009  string("Wf"), 360-longitude());
1010 
1011  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?t"),
1012  string("tf"), theta());
1013  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?T"),
1014  string("Tf"), theta()*DEG_TO_RAD);
1015  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?p"),
1016  string("pf"), phi());
1017  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?P"),
1018  string("Pf"), phi()*DEG_TO_RAD);
1019  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?r"),
1020  string("rf"), radius());
1021  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?R"),
1022  string("Rf"), radius()/1000);
1023  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?h"),
1024  string("hf"), height());
1025  rv = formattedPrint(rv, string("%[ 0-]?[[:digit:]]*(\\.[[:digit:]]+)?H"),
1026  string("Hf"), height()/1000);
1027  return rv;
1028  }
1029 
1030  // Returns the string that operator<<() would print.
1031  string Position::asString() const
1032  {
1033  ostringstream o;
1034  o << *this;
1035  return o.str();
1036  }
1037 
1038  // ----------- Part 10: functions: fundamental conversions ---------------
1039  //
1040  // Fundamental conversion from spherical to cartesian coordinates.
1041  // @param trp (input): theta, phi, radius
1042  // @param xyz (output): X,Y,Z in units of radius
1043  // Algorithm references: standard geometry.
1045  Triple& xyz)
1046  noexcept
1047  {
1048  double st=::sin(tpr[0]*DEG_TO_RAD);
1049  xyz[0] = tpr[2]*st*::cos(tpr[1]*DEG_TO_RAD);
1050  xyz[1] = tpr[2]*st*::sin(tpr[1]*DEG_TO_RAD);
1051  xyz[2] = tpr[2]*::cos(tpr[0]*DEG_TO_RAD);
1052  }
1053 
1054  // Fundamental routine to convert cartesian to spherical coordinates.
1055  // @param xyz (input): X,Y,Z
1056  // @param trp (output): theta, phi (deg), radius in units of input
1057  // Algorithm references: standard geometry.
1059  Triple& tpr)
1060  noexcept
1061  {
1062  tpr[2] = RSS(xyz[0],xyz[1],xyz[2]);
1063  if(tpr[2] <= Position::POSITION_TOLERANCE/5) { // zero-length Cartesian vector
1064  tpr[0] = 90;
1065  tpr[1] = 0;
1066  return;
1067  }
1068  tpr[0] = ::acos(xyz[2]/tpr[2]);
1069  tpr[0] *= RAD_TO_DEG;
1070  if(RSS(xyz[0],xyz[1]) < Position::POSITION_TOLERANCE/5) { // pole
1071  tpr[1] = 0;
1072  return;
1073  }
1074  tpr[1] = ::atan2(xyz[1],xyz[0]);
1075  tpr[1] *= RAD_TO_DEG;
1076  if(tpr[1] < 0) tpr[1] += 360;
1077  }
1078 
1079  // Fundamental routine to convert cartesian (ECEF) to geodetic coordinates,
1080  // (Geoid specified by semi-major axis and eccentricity squared).
1081  // @param xyz (input): X,Y,Z in meters
1082  // @param llh (output): geodetic lat(deg N), lon(deg E),
1083  // height above ellipsoid (meters)
1084  // @param A (input) Earth semi-major axis
1085  // @param eccSq (input) square of Earth eccentricity
1086  // Algorithm references:
1088  Triple& llh,
1089  const double A,
1090  const double eccSq)
1091  noexcept
1092  {
1093  double p,slat,N,htold,latold;
1094  p = SQRT(xyz[0]*xyz[0]+xyz[1]*xyz[1]);
1095  if(p < Position::POSITION_TOLERANCE/5) { // pole or origin
1096  llh[0] = (xyz[2] > 0 ? 90.0: -90.0);
1097  llh[1] = 0; // lon undefined, really
1098  llh[2] = ::fabs(xyz[2]) - A*SQRT(1.0-eccSq);
1099  return;
1100  }
1101  llh[0] = ::atan2(xyz[2], p*(1.0-eccSq));
1102  llh[2] = 0;
1103  for(int i=0; i<5; i++) {
1104  slat = ::sin(llh[0]);
1105  N = A / SQRT(1.0 - eccSq*slat*slat);
1106  htold = llh[2];
1107  llh[2] = p/::cos(llh[0]) - N;
1108  latold = llh[0];
1109  llh[0] = ::atan2(xyz[2], p*(1.0-eccSq*(N/(N+llh[2]))));
1110  if(::fabs(llh[0]-latold) < 1.0e-9 && fabs(llh[2]-htold) < 1.0e-9 * A) break;
1111  }
1112  llh[1] = ::atan2(xyz[1],xyz[0]);
1113  if(llh[1] < 0.0) llh[1] += TWO_PI;
1114  llh[0] *= RAD_TO_DEG;
1115  llh[1] *= RAD_TO_DEG;
1116  }
1117 
1118  // Fundamental routine to convert geodetic to cartesian (ECEF) coordinates,
1119  // (Geoid specified by semi-major axis and eccentricity squared).
1120  // @param llh (input): geodetic lat(deg N), lon(deg E),
1121  // height above ellipsoid (meters)
1122  // @param xyz (output): X,Y,Z in meters
1123  // @param A (input) Earth semi-major axis
1124  // @param eccSq (input) square of Earth eccentricity
1125  // Algorithm references:
1127  Triple& xyz,
1128  const double A,
1129  const double eccSq)
1130  noexcept
1131  {
1132  double slat = ::sin(llh[0]*DEG_TO_RAD);
1133  double clat = ::cos(llh[0]*DEG_TO_RAD);
1134  double N = A/SQRT(1.0-eccSq*slat*slat);
1135  xyz[0] = (N+llh[2])*clat*::cos(llh[1]*DEG_TO_RAD);
1136  xyz[1] = (N+llh[2])*clat*::sin(llh[1]*DEG_TO_RAD);
1137  xyz[2] = (N*(1.0-eccSq)+llh[2])*slat;
1138  }
1139 
1140  // Fundamental routine to convert cartesian (ECEF) to geocentric coordinates.
1141  // @param xyz (input): X,Y,Z in meters
1142  // @param llr (output):
1143  // geocentric lat(deg N),lon(deg E),radius (units of input)
1145  Triple& llr)
1146  noexcept
1147  {
1148  convertCartesianToSpherical(xyz, llr);
1149  llr[0] = 90 - llr[0]; // convert theta to latitude
1150  }
1151 
1152  // Fundamental routine to convert geocentric to cartesian (ECEF) coordinates.
1153  // @param llr (input): geocentric lat(deg N),lon(deg E),radius
1154  // @param xyz (output): X,Y,Z (units of radius)
1156  Triple& xyz)
1157  noexcept
1158  {
1159  Triple llh(llr);
1160  llh[0] = 90 - llh[0]; // convert latitude to theta
1161  convertSphericalToCartesian(llh, xyz);
1162  }
1163 
1164  // Fundamental routine to convert geocentric to geodetic coordinates.
1165  // @param llr (input): geocentric Triple: lat(deg N),lon(deg E),radius (meters)
1166  // @param llh (output): geodetic latitude (deg N),
1167  // longitude (deg E), and height above ellipsoid (meters)
1168  // @param A (input) Earth semi-major axis
1169  // @param eccSq (input) square of Earth eccentricity
1171  Triple& llh,
1172  const double A,
1173  const double eccSq)
1174  noexcept
1175  {
1176  double cl,p,sl,slat,N,htold,latold;
1177  llh[1] = llr[1]; // longitude is unchanged
1178  cl = ::sin((90-llr[0])*DEG_TO_RAD);
1179  sl = ::cos((90-llr[0])*DEG_TO_RAD);
1180  if(llr[2] <= Position::POSITION_TOLERANCE/5) {
1181  // radius is below tolerance, hence assign zero-length
1182  // arbitrarily set latitude = longitude = 0
1183  llh[0] = llh[1] = 0;
1184  llh[2] = -A;
1185  return;
1186  }
1187  else if(cl < 1.e-10) {
1188  // near pole ... note that 1mm/radius(Earth) = 1.5e-10
1189  if(llr[0] < 0) llh[0] = -90;
1190  else llh[0] = 90;
1191  llh[1] = 0;
1192  llh[2] = llr[2] - A*SQRT(1-eccSq);
1193  return;
1194  }
1195  llh[0] = ::atan2(sl, cl*(1.0-eccSq));
1196  p = cl*llr[2];
1197  llh[2] = 0;
1198  for(int i=0; i<5; i++) {
1199  slat = ::sin(llh[0]);
1200  N = A / SQRT(1.0 - eccSq*slat*slat);
1201  htold = llh[2];
1202  llh[2] = p/::cos(llh[0]) - N;
1203  latold = llh[0];
1204  llh[0] = ::atan2(sl, cl*(1.0-eccSq*(N/(N+llh[2]))));
1205  if(fabs(llh[0]-latold) < 1.0e-9 && ::fabs(llh[2]-htold) < 1.0e-9 * A) break;
1206  }
1207  llh[0] *= RAD_TO_DEG;
1208  }
1209 
1210  // Fundamental routine to convert geodetic to geocentric coordinates.
1211  // @param geodeticllh (input): geodetic latitude (deg N),
1212  // longitude (deg E), and height above ellipsoid (meters)
1213  // @param llr (output): geocentric lat (deg N),lon (deg E),radius (meters)
1214  // @param A (input) Earth semi-major axis
1215  // @param eccSq (input) square of Earth eccentricity
1217  Triple& llr,
1218  const double A,
1219  const double eccSq)
1220  noexcept
1221  {
1222  double slat = ::sin(llh[0]*DEG_TO_RAD);
1223  double N = A/SQRT(1.0-eccSq*slat*slat);
1224  // longitude is unchanged
1225  llr[1] = llh[1];
1226  // radius
1227  llr[2] = SQRT((N+llh[2])*(N+llh[2]) + N*eccSq*(N*eccSq-2*(N+llh[2]))*slat*slat);
1228  if(llr[2] <= Position::POSITION_TOLERANCE/5) {
1229  // radius is below tolerance, hence assign zero-length
1230  // arbitrarily set latitude = longitude = 0
1231  llr[0] = llr[1] = llr[2] = 0;
1232  return;
1233  }
1234  if(1-::fabs(slat) < 1.e-10) { // at the pole
1235  if(slat < 0) llr[0] = -90;
1236  else llr[0] = 90;
1237  llr[1] = 0.0;
1238  return;
1239  }
1240  // theta
1241  llr[0] = ::acos((N*(1-eccSq)+llh[2])*slat/llr[2]);
1242  llr[0] *= RAD_TO_DEG;
1243  llr[0] = 90 - llr[0];
1244  }
1245 
1246  // ----------- Part 11: operator<< and other useful functions -------------
1247  //
1248  // Stream output for Position objects.
1249  // @param s stream to append formatted Position to.
1250  // @param t Position to append to stream \c s.
1251  // @return reference to \c s.
1252  ostream& operator<<(ostream& s, const Position& p)
1253  {
1254  if(p.system == Position::Cartesian)
1255  s << p.printf("%.4x m %.4y m %.4z m");
1256  else if(p.system == Position::Geodetic)
1257  s << p.printf("%.8A degN %.8L degE %.4h m");
1258  else if(p.system == Position::Geocentric)
1259  s << p.printf("%.8a degN %.8L degE %.4r m");
1260  else if(p.system == Position::Spherical)
1261  s << p.printf("%.8t deg %.8p deg %.4r m");
1262  else
1263  s << " Unknown system! : " << p[0] << " " << p[1] << " " << p[2];
1264 
1265  return s;
1266  }
1267 
1268  // Compute the range in meters between this Position and
1269  // the Position passed as input.
1270  // @param right Position to which to find the range
1271  // @return the range (in meters)
1272  // @throw GeometryException if ell values differ
1273  double range(const Position& A,
1274  const Position& B)
1275  {
1276  if(A.AEarth != B.AEarth || A.eccSquared != B.eccSquared)
1277  {
1278  GeometryException ge("Unequal geoids");
1279  GNSSTK_THROW(ge);
1280  }
1281 
1282  Position L(A),R(B);
1283  L.transformTo(Position::Cartesian);
1285  double dif = RSS(L.X()-R.X(),L.Y()-R.Y(),L.Z()-R.Z());
1286  return dif;
1287  }
1288 
1289  // Compute the radius of the ellipsoidal Earth, given the geodetic latitude.
1290  // @param geolat geodetic latitude in degrees
1291  // @return the Earth radius (in meters)
1292  double Position::radiusEarth(const double geolat,
1293  const double A,
1294  const double eccSq)
1295  noexcept
1296  {
1297  double slat=::sin(DEG_TO_RAD*geolat);
1298  double e=(1.0-eccSq);
1299  double f=(1.0+(e*e-1.0)*slat*slat)/(1.0-eccSq*slat*slat);
1300  return (A * SQRT(f));
1301  }
1302 
1303  // A member function that computes the elevation of the input
1304  // (Target) position as seen from this Position.
1305  // @param Target the Position which is observed to have the
1306  // computed elevation, as seen from this Position.
1307  // @return the elevation in degrees
1308  double Position::elevation(const Position& Target) const
1309  {
1310  Position R(*this),S(Target);
1311  R.transformTo(Cartesian);
1312  S.transformTo(Cartesian);
1313  // use Triple:: functions in cartesian coordinates (only)
1314  double elevation;
1315  try {
1316  elevation = R.elvAngle(S);
1317  }
1318  catch(GeometryException& ge)
1319  {
1320  GNSSTK_RETHROW(ge);
1321  }
1322  return elevation;
1323  }
1324 
1325  // A member function that computes the elevation of the input
1326  // (Target) position as seen from this Position, using a Geodetic
1327  // (i.e. ellipsoidal) system.
1328  // @param Target the Position which is observed to have the
1329  // computed elevation, as seen from this Position.
1330  // @return the elevation in degrees
1331  double Position::elevationGeodetic(const Position& Target) const
1332  {
1333  Position R(*this),S(Target);
1334  double latGeodetic = R.getGeodeticLatitude()*DEG_TO_RAD;
1335  double longGeodetic = R.getLongitude()*DEG_TO_RAD;
1336  double localUp;
1337  double cosUp;
1338  R.transformTo(Cartesian);
1339  S.transformTo(Cartesian);
1340  Triple z;
1341  // Let's get the slant vector
1342  z = S.theArray - R.theArray;
1343 
1344  if (z.mag()<=1e-4) // if the positions are within .1 millimeter
1345  {
1346  GeometryException ge("Positions are within .1 millimeter");
1347  GNSSTK_THROW(ge);
1348  }
1349 
1350  // Compute k vector in local North-East-Up (NEU) system
1351  Triple kVector(::cos(latGeodetic)*::cos(longGeodetic), ::cos(latGeodetic)*::sin(longGeodetic), ::sin(latGeodetic));
1352  // Take advantage of dot method to get Up coordinate in local NEU system
1353  localUp = z.dot(kVector);
1354  // Let's get cos(z), being z the angle with respect to local vertical (Up);
1355  cosUp = localUp/z.mag();
1356 
1357  return 90.0 - ((::acos(cosUp))*RAD_TO_DEG);
1358  }
1359 
1360  // A member function that computes the azimuth of the input
1361  // (Target) position as seen from this Position.
1362  // @param Target the Position which is observed to have the
1363  // computed azimuth, as seen from this Position.
1364  // @return the azimuth in degrees
1365  double Position::azimuth(const Position& Target) const
1366  {
1367  Position R(*this),S(Target);
1368  R.transformTo(Cartesian);
1369  S.transformTo(Cartesian);
1370  // use Triple:: functions in cartesian coordinates (only)
1371  double az;
1372  try
1373  {
1374  az = R.azAngle(S);
1375 
1376  }
1377  catch(GeometryException& ge)
1378  {
1379  GNSSTK_RETHROW(ge);
1380  }
1381 
1382  return az;
1383  }
1384 
1385  // A member function that computes the azimuth of the input
1386  // (Target) position as seen from this Position, using a Geodetic
1387  // (i.e. ellipsoidal) system.
1388  // @param Target the Position which is observed to have the
1389  // computed azimuth, as seen from this Position.
1390  // @return the azimuth in degrees
1391  double Position::azimuthGeodetic(const Position& Target) const
1392  {
1393  Position R(*this),S(Target);
1394  double latGeodetic = R.getGeodeticLatitude()*DEG_TO_RAD;
1395  double longGeodetic = R.getLongitude()*DEG_TO_RAD;
1396  double localN, localE;
1397  R.transformTo(Cartesian);
1398  S.transformTo(Cartesian);
1399  Triple z;
1400  // Let's get the slant vector
1401  z = S.theArray - R.theArray;
1402 
1403  if (z.mag()<=1e-4) // if the positions are within .1 millimeter
1404  {
1405  GeometryException ge("Positions are within .1 millimeter");
1406  GNSSTK_THROW(ge);
1407  }
1408 
1409  // Compute i vector in local North-East-Up (NEU) system
1410  Triple iVector(-::sin(latGeodetic)*::cos(longGeodetic), -::sin(latGeodetic)*::sin(longGeodetic), ::cos(latGeodetic));
1411  // Compute j vector in local North-East-Up (NEU) system
1412  Triple jVector(-::sin(longGeodetic), ::cos(longGeodetic), 0);
1413 
1414  // Now, let's use dot product to get localN and localE unitary vectors
1415  localN = (z.dot(iVector))/z.mag();
1416  localE = (z.dot(jVector))/z.mag();
1417 
1418  // Let's test if computing azimuth has any sense
1419  double test = fabs(localN) + fabs(localE);
1420 
1421  // Warning: If elevation is very close to 90 degrees, we will return azimuth = 0.0
1422  if (test < 1.0e-16) return 0.0;
1423 
1424  double alpha = ((::atan2(localE, localN)) * RAD_TO_DEG);
1425  if (alpha < 0.0)
1426  {
1427  return alpha + 360.0;
1428  }
1429  else
1430  {
1431  return alpha;
1432  }
1433  }
1434 
1435  // A member function that computes the point at which a signal, which
1436  // is received at *this Position and there is observed at the input
1437  // azimuth and elevation, crosses a model ionosphere that is taken to
1438  // be a uniform thin shell at the input height. This algorithm is done
1439  // in geocentric coordinates.
1440  // A member function that computes the point at which a signal, which
1441  // is received at *this Position and there is observed at the input
1442  // azimuth and elevation, crosses a model ionosphere that is taken to
1443  // be a uniform thin shell at the input height. This algorithm is done
1444  // in geocentric coordinates.
1445  // @param elev elevation angle of the signal at reception, in degrees
1446  // @param azim azimuth angle of the signal at reception, in degrees
1447  // @param ionoht height of the ionosphere, in meters
1448  // @return Position IPP the position of the ionospheric pierce point,
1449  // in the same coordinate system as *this; *this is not modified.
1451  const double azim,
1452  const double ionoht) const
1453  noexcept
1454  {
1455  Position Rx(*this);
1456 
1457  // convert to Geocentric
1458  Rx.transformTo(Geocentric);
1459 
1460  // compute the geographic pierce point
1461  Position IPP(Rx); // copy system and geoid
1462  double el = elev * DEG_TO_RAD;
1463  // p is the angle subtended at Earth center by Rx and the IPP
1464  double p = PI/2.0 - el - ::asin(AEarth*::cos(el)/(AEarth+ionoht));
1465  double lat = Rx.theArray[0] * DEG_TO_RAD;
1466  double az = azim * DEG_TO_RAD;
1467  IPP.theArray[0] = std::asin(std::sin(lat)*std::cos(p) + std::cos(lat)*std::sin(p)*std::cos(az));
1468  IPP.theArray[1] = Rx.theArray[1]*DEG_TO_RAD
1469  + ::asin(::sin(p)*::sin(az)/::cos(IPP.theArray[0]));
1470 
1471  IPP.theArray[0] *= RAD_TO_DEG;
1472  IPP.theArray[1] *= RAD_TO_DEG;
1473  IPP.theArray[2] = AEarth + ionoht;
1474 
1475  // transform back
1476  IPP.transformTo(system);
1477 
1478  return IPP;
1479  }
1480 
1481 
1488  noexcept
1489  {
1490 
1491  double slat = ::sin(geodeticLatitude()*DEG_TO_RAD);
1492  double W = 1.0/SQRT(1.0-eccSquared*slat*slat);
1493 
1494  return AEarth*(1.0-eccSquared)*W*W*W;
1495 
1496  }
1497 
1504  noexcept
1505  {
1506 
1507  double slat = ::sin(geodeticLatitude()*DEG_TO_RAD);
1508 
1509  return AEarth/SQRT(1.0-eccSquared*slat*slat);
1510 
1511  }
1512 
1513 
1515  const
1516  {
1517  Position p1(*this), p2(target);
1518  p1.transformTo(Geodetic);
1519  p2.transformTo(Geodetic);
1520  Angle phi1(p1.geodeticLatitude(), AngleType::Deg);
1521  Angle lambda1(p1.longitude(), AngleType::Deg);
1523  Angle lambda2(p2.longitude(), AngleType::Deg);
1524  // radius requires spherical coordinates, so get them from
1525  // the original Position objects in the off-chance they were
1526  // already in the spherical system (we can be guaranteed p1
1527  // and p2 will not be).
1528  double r1 = radius();
1529  double r2 = target.radius();
1530  return getZenithAngle(phi1, lambda1, phi2, lambda2, r1, r2, delta);
1531  }
1532 
1533 
1535  getZenithAngle(const Angle& phi1, const Angle& lambda1,
1536  const Angle& phi2, const Angle& lambda2,
1537  double r1, double r2,
1538  AngleReduced& delta)
1539  {
1541  // reference \cite galileo:iono though probably not exclusively
1542  delta.setValue(sin(phi1)*sin(phi2) + //eq.153
1543  cos(phi1)*cos(phi2)*cos(lambda2-lambda1),
1544  AngleType::Cos);
1545  DEBUGTRACE("delta.sin=" << scientific << delta.sin());
1546  DEBUGTRACE("delta.cos=" << scientific << delta.cos());
1547  return Angle(atan2(sin(delta),cos(delta) - (r1/r2)), //eq.155
1548  AngleType::Rad);
1549  }
1550 
1551 
1553  {
1555  // reference \cite galileo:iono though probably not exclusively
1556  Position p1(*this), p2(target);
1557  p1.transformTo(Geodetic);
1558  p2.transformTo(Geodetic);
1559  Angle phi1(p1.geodeticLatitude(), AngleType::Deg);
1560  Angle lambda1(p1.longitude(), AngleType::Deg);
1562  Angle lambda2(p2.longitude(), AngleType::Deg);
1563  // radius requires spherical coordinates, so get them from
1564  // the original Position objects in the off-chance they were
1565  // already in the spherical system (we can be guaranteed p1
1566  // and p2 will not be).
1567  // Also convert from m to km for the formulae below.
1568  double r1 = radius() / 1000.0;
1569  double r2 = target.radius() / 1000.0;
1570  AngleReduced delta;
1571  Angle zeta = getZenithAngle(phi1,lambda1,phi2,lambda2,r1,r2,delta);
1572  double rp = r1 * sin(zeta); //eq.156
1573  DEBUGTRACE(setprecision(20) << "pStation_position->radius_km=" << scientific << r1);
1574  DEBUGTRACE("pZenith_angle->sin=" << scientific << sin(zeta));
1575  DEBUGTRACE("pRay->slant.perigee_radius_km=" << scientific << rp);
1576  Angle phiP, lambdaP;
1577  if (fabs(fabs(phi1.deg())-90) < 1e-10)
1578  {
1579  phiP = (phi1.deg() > 0) ? zeta : -zeta; //eq.157
1580  lambdaP.setValue((zeta.rad() >= 0) ? lambda2.rad() + PI : //eq.164
1581  lambda2.rad(), AngleType::Rad);
1582  }
1583  else
1584  {
1585  AngleReduced sigma(
1586  (sin(lambda2-lambda1) * cos(phi2)) / sin(delta), //eq.158
1587  ((sin(phi2) - (cos(delta)*sin(phi1))) / //eq.159
1588  (sin(delta) * cos(phi1))));
1589  Angle deltaP(PI/2.0 - zeta.rad(), AngleType::Rad); //eq.160
1590  phiP.setValue(sin(phi1)*cos(deltaP) - //eq.161
1591  cos(phi1)*sin(deltaP)*cos(sigma), AngleType::Sin);
1592  Angle dLambda(-(sin(sigma)*sin(deltaP))/cos(phiP), //eq.165
1593  ((cos(deltaP)-sin(phi1)*sin(phiP)) / //eq.166
1594  (cos(phi1)*cos(phiP))));
1595  lambdaP = dLambda + lambda1; //eq.167
1596  }
1597  // rp is in km, convert to meters for Position
1598  Position rv(phiP.deg(), lambdaP.deg(), rp*1000.0, Geocentric);
1599  rv.copyEllipsoidModelFrom(*this);
1600  return rv;
1601  }
1602 
1603 
1604  Position Position::getRayPosition(double dist, const Position& target) const
1605  {
1607  // reference \cite galileo:iono though probably not exclusively
1608  Position p2(target);
1609  p2.transformTo(Geodetic);
1610  Position pp(getRayPerigee(target));
1612  Angle lambda2(p2.longitude(), AngleType::Deg);
1614  Angle lambdap(pp.longitude(), AngleType::Deg);
1615  Angle dLambda(lambda2 - lambdap);
1616  AngleReduced psi;
1617  AngleReduced sigmap;
1618  DEBUGTRACE("# pRay->latitude.rad=" << scientific << phip.rad());
1619  DEBUGTRACE("# pRay->latitude.degree=" << scientific << phip.deg());
1620  DEBUGTRACE("# pRay->latitude.sin=" << scientific << phip.sin());
1621  DEBUGTRACE("# pRay->latitude.cos=" << scientific << phip.cos());
1622  DEBUGTRACE("# pRay->longitude.rad=" << scientific << lambdap.rad());
1623  DEBUGTRACE("# pRay->longitude.degree=" << scientific << lambdap.deg());
1624  DEBUGTRACE("pRay->longitude.sin=" << scientific << lambdap.sin());
1625  DEBUGTRACE("pRay->longitude.cos=" << scientific << lambdap.cos());
1626  DEBUGTRACE("# pRay->satellite_position.latitude.rad=" << scientific << phi2.rad());
1627  DEBUGTRACE("# pRay->satellite_position.latitude.degree=" << scientific << phi2.deg());
1628  DEBUGTRACE("# pRay->satellite_position.latitude.sin=" << scientific << phi2.sin());
1629  DEBUGTRACE("# pRay->satellite_position.latitude.cos=" << scientific << phi2.cos());
1630  DEBUGTRACE("# pRay->satellite_position.longitude.rad=" << scientific << lambda2.rad());
1631  DEBUGTRACE("# pRay->satellite_position.longitude.degree=" << scientific << lambda2.deg());
1632  DEBUGTRACE("# pRay->satellite_position.longitude.sin=" << scientific << lambda2.sin());
1633  DEBUGTRACE("# pRay->satellite_position.longitude.cos=" << scientific << lambda2.cos());
1634  if (fabs(fabs(phip.deg())-90.0) < 1e-10)
1635  {
1636  psi.setValue(fabs(p2.geodeticLatitude()-pp.geodeticLatitude()),//eq.168
1637  AngleType::Deg);
1638  if (phip.deg() > 0)
1639  {
1640  sigmap = Angle(0.0, -1.0); //eq.173
1641  }
1642  else
1643  {
1644  // note that the equation says >0 or <0 but not ==0,
1645  // but the EU code does it this way as well (see
1646  // NeQuickG_JRC_ray.c, get_azimuth())
1647  sigmap = Angle(0.0, 1.0); //eq.173
1648  }
1649  }
1650  else
1651  {
1652  psi = AngleReduced(sin(phip)*sin(phi2) + //eq.169
1653  cos(phip)*cos(phi2)*cos(dLambda), AngleType::Cos);
1654  sigmap = AngleReduced(cos(phi2)*sin(dLambda)/sin(psi), //eq.174
1655  (sin(phi2)-sin(phip)*cos(psi)) / //eq.175
1656  (cos(phip)*sin(psi)));
1657  }
1658  DEBUGTRACE("# psi_angle.sin=" << scientific << psi.sin());
1659  DEBUGTRACE("# psi_angle.cos=" << scientific << psi.cos());
1660  DEBUGTRACE("# pRay->slant.azimuth.sin=" << scientific << sigmap.sin());
1661  DEBUGTRACE("# pRay->slant.azimuth.cos=" << scientific << sigmap.cos());
1662  double rp = pp.radius(); // radius in m
1663  // rs is also in meters now rather than km per the equation,
1664  // because the Position class prefers meters. Also computing
1665  // as a geocentric radius so as to avoid dealing with
1666  // EllipsoidModels.
1667  double rs = sqrt(dist*dist + rp*rp); //eq.178
1668  double tanDeltas = dist / rp; //eq.179
1669  double cosDeltas = 1/sqrt(1+tanDeltas*tanDeltas); //eq.180
1670  double sinDeltas = tanDeltas * cosDeltas; //eq.181
1671  Angle phis(sin(phip)*cosDeltas + cos(phip)*sinDeltas*cos(sigmap), //eq.182
1672  AngleType::Sin);
1673  Angle dlambda(sinDeltas*sin(sigmap)*cos(phip), //eq.185
1674  cosDeltas-sin(phip)*sin(phis)); //eq.186
1675  double lambdas = dlambda.deg() + lambdap.deg(); //eq.187
1676  Position rv(phis.deg(), lambdas, rs, Geocentric);
1677  // Still need to copy the ellipsoid model so that any
1678  // coordinate system conversions done by the user don't give
1679  // unexpected results
1680  rv.copyEllipsoidModelFrom(*this);
1681  DEBUGTRACE("current_position.radius_km=" << scientific << (rs / 1000.0));
1682  DEBUGTRACE("current_position.height=" << scientific << (rv.height() / 1000.0));
1683  DEBUGTRACE("current_position.latitude.rad=" << scientific << phis.rad());
1684  DEBUGTRACE("current_position.latitude.degree=" << scientific << phis.deg());
1685  DEBUGTRACE("current_position.latitude.sin=" << scientific << phis.sin());
1686  DEBUGTRACE("current_position.latitude.cos=" << scientific << phis.cos());
1687  DEBUGTRACE("current_position.longitude.degree=" << scientific << lambdas);
1688  return rv;
1689  }
1690 
1691 
1692  // ----------- Part 12: private functions and member data -----------------
1693  //
1694  // Initialization function, used by the constructors.
1695  // @param a coordinate [ X(m), or latitude (degrees N) ]
1696  // @param b coordinate [ Y(m), or longitude (degrees E) ]
1697  // @param c coordinate [ Z, height above ellipsoid or radius, in m ]
1698  // @param s CoordinateSystem, defaults to Cartesian
1699  // @param geiod pointer to a GeoidModel, default NULL (WGS84)
1700  // @throw GeometryException on invalid input.
1701  void Position::initialize(const double a,
1702  const double b,
1703  const double c,
1705  const EllipsoidModel *ell,
1706  const RefFrame& frame)
1707  {
1708  double bb(b);
1709  if(s == Geodetic || s==Geocentric)
1710  {
1711  if(a > 90 || a < -90)
1712  {
1713  GeometryException ge("Invalid latitude in constructor: "
1714  + StringUtils::asString(a));
1715  GNSSTK_THROW(ge);
1716  }
1717  if(bb < 0)
1718  bb += 360*(1+(unsigned long)(bb/360));
1719  else if(bb >= 360)
1720  bb -= 360*(unsigned long)(bb/360);
1721  }
1722  if(s==Geocentric || s==Spherical)
1723  {
1724  if(c < 0)
1725  {
1726  GeometryException ge("Invalid radius in constructor: "
1727  + StringUtils::asString(c));
1728  GNSSTK_THROW(ge);
1729  }
1730  }
1731  if(s==Spherical)
1732  {
1733  if(a < 0 || a > 180)
1734  {
1735  GeometryException ge("Invalid theta in constructor: "
1736  + StringUtils::asString(a));
1737  GNSSTK_THROW(ge);
1738  }
1739  if(bb < 0)
1740  bb += 360*(1+(unsigned long)(bb/360));
1741  else if(bb >= 360)
1742  bb -= 360*(unsigned long)(bb/360);
1743  }
1744 
1745  theArray[0] = a;
1746  theArray[1] = bb;
1747  theArray[2] = c;
1748 
1749  if(ell) {
1750  AEarth = ell->a();
1751  eccSquared = ell->eccSquared();
1752  }
1753  else {
1755  AEarth = WGS84.a();
1756  eccSquared = WGS84.eccSquared();
1757  }
1758  system = s;
1759  tolerance = POSITION_TOLERANCE;
1760  refFrame = frame;
1761  }
1762 
1763 } // namespace gnsstk
gnsstk::Position::Geodetic
@ Geodetic
geodetic latitude, longitude, and height above ellipsoid
Definition: Position.hpp:145
gnsstk::Position::setGeocentric
Position & setGeocentric(const double lat, const double lon, const double rad)
Definition: Position.cpp:531
gnsstk::Position::radiusEarth
double radiusEarth() const noexcept
Definition: Position.hpp:841
gnsstk::StringUtils::asInt
long asInt(const std::string &s)
Definition: StringUtils.hpp:713
gnsstk::Position::copyEllipsoidModelFrom
void copyEllipsoidModelFrom(const Position &src)
Definition: Position.hpp:1018
gnsstk::AngleReduced
Definition: AngleReduced.hpp:60
gnsstk::operator==
bool operator==(const IonexData::IonexValType &x, const IonexData::IonexValType &y)
operator == for IonexData::IonexValType
Definition: IonexData.hpp:253
gnsstk::Position::Cartesian
@ Cartesian
cartesian (Earth-centered, Earth-fixed)
Definition: Position.hpp:147
gnsstk::Angle::rad
double rad() const
Get the angle in radians.
Definition: Angle.hpp:94
gnsstk::EllipsoidModel::eccSquared
virtual double eccSquared() const noexcept
Definition: EllipsoidModel.hpp:72
SQRT
#define SQRT(x)
Definition: MathBase.hpp:74
gnsstk::Position::transformTo
Position & transformTo(CoordinateSystem sys) noexcept
Definition: Position.cpp:247
const
#define const
Definition: getopt.c:43
gnsstk::Position::initialize
void initialize(const double a, const double b, const double c, CoordinateSystem s=Cartesian, const EllipsoidModel *ell=nullptr, const RefFrame &frame=RefFrame())
Definition: Position.cpp:1701
gnsstk::Position::setReferenceFrame
void setReferenceFrame(const RefFrame &frame) noexcept
Definition: Position.cpp:467
gnsstk::Position::Position
Position() noexcept
Definition: Position.cpp:92
gnsstk::operator+
SparseMatrix< T > operator+(const SparseMatrix< T > &L, const SparseMatrix< T > &R)
Matrix addition: SparseMatrix = SparseMatrix + SparseMatrix : copy, += SM.
Definition: SparseMatrix.hpp:1608
WGS84Ellipsoid.hpp
gnsstk::AngleReduced::sin
double sin() const
Get the sine of this angle.
Definition: AngleReduced.hpp:94
DEBUGTRACE
#define DEBUGTRACE(EXPR)
Definition: DebugTrace.hpp:119
gnsstk::TrackingCode::Y
@ Y
Encrypted legacy GPS precise code.
gnsstk::Position::geocentricLatitude
double geocentricLatitude() const noexcept
Definition: Position.cpp:398
Angle.hpp
gnsstk::Position::setTolerance
Position & setTolerance(const double tol) noexcept
Definition: Position.cpp:82
gnsstk::Position::system
CoordinateSystem system
see CoordinateSystem
Definition: Position.hpp:1068
gnsstk::Position::convertGeocentricToCartesian
static void convertGeocentricToCartesian(const Triple &llr, Triple &xyz) noexcept
Definition: Position.cpp:1155
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
Position.hpp
gnsstk::Position::Y
double Y() const noexcept
return Y coordinate (meters)
Definition: Position.cpp:364
gnsstk::Position::Z
double Z() const noexcept
return Z coordinate (meters)
Definition: Position.cpp:375
NULL
#define NULL
Definition: getopt1.c:64
gnsstk::Position::setSpherical
Position & setSpherical(const double theta, const double phi, const double rad)
Definition: Position.cpp:566
gnsstk::TWO_PI
const double TWO_PI
GPS value of PI*2.
Definition: GNSSconstants.hpp:68
gnsstk::PI
const double PI
GPS value of PI; also specified by GAL.
Definition: GNSSconstants.hpp:62
gnsstk::Position::setToString
Position & setToString(const std::string &str, const std::string &fmt)
Definition: Position.cpp:658
gnsstk::Triple::theArray
std::valarray< double > theArray
Definition: Triple.hpp:251
GNSSconstants.hpp
gnsstk::RefFrame
Definition: RefFrame.hpp:53
gnsstk::Triple
Definition: Triple.hpp:68
gnsstk::Position::setEllipsoidModel
void setEllipsoidModel(const EllipsoidModel *ell)
Definition: Position.cpp:478
gnsstk::Position::height
double height() const noexcept
return height above ellipsoid (meters) (Geodetic).
Definition: Position.cpp:455
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::IonexStoreStrategy::Unknown
@ Unknown
Unknown or uninitialized stategy value.
gnsstk::StringUtils::stripLeading
std::string & stripLeading(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1426
gnsstk::Angle
Definition: Angle.hpp:53
gnsstk::Position::azimuth
double azimuth(const Position &Target) const
Definition: Position.cpp:1365
gnsstk::Position::printf
std::string printf(const char *fmt) const
Definition: Position.cpp:982
std::sin
double sin(gnsstk::Angle x)
Definition: Angle.hpp:144
gnsstk::Position::convertCartesianToGeodetic
static void convertCartesianToGeodetic(const Triple &xyz, Triple &llh, const double A, const double eccSq) noexcept
Definition: Position.cpp:1087
gnsstk::AngleReduced::setValue
void setValue(double v, AngleType t)
Definition: AngleReduced.cpp:53
gnsstk::Position::geodeticLatitude
double geodeticLatitude() const noexcept
return geodetic latitude (degrees North).
Definition: Position.cpp:386
gnsstk::Position::azimuthGeodetic
double azimuthGeodetic(const Position &Target) const
Definition: Position.cpp:1391
gnsstk::SystemNames
static const char * SystemNames[]
Definition: Position.cpp:55
MiscMath.hpp
gnsstk::WGS84Ellipsoid
Definition: WGS84Ellipsoid.hpp:56
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::AngleType::Rad
@ Rad
Value is in radians.
gnsstk::StringUtils::stripTrailing
std::string & stripTrailing(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1453
gnsstk::Position::setECEF
Position & setECEF(const double X, const double Y, const double Z) noexcept
Definition: Position.cpp:601
gnsstk::Position::getReferenceFrame
const RefFrame & getReferenceFrame() const noexcept
return coordinate RefFrame
Definition: Position.cpp:346
gnsstk::Triple::dot
double dot(const Triple &right) const noexcept
Definition: Triple.cpp:107
initialize
int initialize(string &errors)
Definition: RinEdit.cpp:513
gnsstk::AngleType::Sin
@ Sin
Value is the sine of the angle.
gnsstk::RAD_TO_DEG
static const double RAD_TO_DEG
Conversion Factor from radians to degrees (units: degrees)
Definition: GNSSconstants.hpp:78
y
page HOWTO subpage DoxygenGuide Documenting Your Code page DoxygenGuide Documenting Your Code todo Flesh out this document section doctips Tips for Documenting When defining make sure that the prototype is identical between the cpp and hpp including both the namespaces and the parameter names for you have std::string as the return type in the hpp file and string as the return type in the cpp Doxygen may get confused and autolink to the cpp version with no documentation If you don t use the same parameter names between the cpp and hpp that will also confuse Doxygen Don t put type information in return or param documentation It doesn t really add anything and will often cause Doxygen to complain and not produce the documentation< br > use note Do not put a comma after a param name unless you mean to document multiple parameters< br/> the output stream</code >< br/> y
Definition: DOCUMENTING.dox:15
gnsstk::Position::getZenithAngle
Angle getZenithAngle(const Position &target, AngleReduced &delta) const
Definition: Position.cpp:1514
gnsstk::Position::ONE_MM_TOLERANCE
static const GNSSTK_EXPORT double ONE_MM_TOLERANCE
One millimeter tolerance.
Definition: Position.hpp:158
gnsstk::Position::convertGeodeticToGeocentric
static void convertGeodeticToGeocentric(const Triple &geodeticllh, Triple &llr, const double A, const double eccSq) noexcept
Definition: Position.cpp:1216
gnsstk::Position::radius
double radius() const noexcept
Definition: Position.cpp:444
gnsstk::Position::Geocentric
@ Geocentric
geocentric (regular spherical coordinates)
Definition: Position.hpp:146
gnsstk::AngleType::Cos
@ Cos
Value is the cosine of the angle.
gnsstk::Position::phi
double phi() const noexcept
return spherical coordinate phi in degrees
Definition: Position.cpp:420
gnsstk::AngleReduced::cos
double cos() const
Get the cosine of this angle.
Definition: AngleReduced.hpp:98
gnsstk::Position::ONE_CM_TOLERANCE
static const GNSSTK_EXPORT double ONE_CM_TOLERANCE
One centimeter tolerance.
Definition: Position.hpp:160
gnsstk::Position::getCurvMeridian
double getCurvMeridian() const noexcept
Definition: Position.cpp:1487
gnsstk::operator<<
std::ostream & operator<<(std::ostream &s, const ObsEpoch &oe) noexcept
Definition: ObsEpochMap.cpp:54
gnsstk::Position::asString
std::string asString() const
Definition: Position.cpp:1031
gnsstk::Position::Spherical
@ Spherical
spherical coordinates (theta,phi,radius)
Definition: Position.hpp:148
gnsstk::RefFrameSys::WGS84
@ WGS84
The reference frame used by GPS.
gnsstk::AngleType::Deg
@ Deg
Value is in degrees.
gnsstk::Xvt
Definition: Xvt.hpp:60
gnsstk::Position::operator+=
Position & operator+=(const Position &right) noexcept
Definition: Position.cpp:173
gnsstk::Angle::deg
double deg() const
Get the angle in degrees.
Definition: Angle.hpp:98
gnsstk::Position::CoordinateSystem
CoordinateSystem
The coordinate systems supported by Position.
Definition: Position.hpp:142
std::cos
double cos(gnsstk::Angle x)
Definition: Angle.hpp:146
gnsstk::Position::ONE_UM_TOLERANCE
static const GNSSTK_EXPORT double ONE_UM_TOLERANCE
One micron tolerance.
Definition: Position.hpp:162
gnsstk::StringUtils::asDouble
double asDouble(const std::string &s)
Definition: StringUtils.hpp:705
gnsstk::RSS
T RSS(T aa, T bb, T cc)
Perform the root sum square of aa, bb and cc.
Definition: MiscMath.hpp:246
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
gnsstk::Position::POSITION_TOLERANCE
static GNSSTK_EXPORT double POSITION_TOLERANCE
Default tolerance for time equality in days.
Definition: Position.hpp:165
gnsstk::Position::AEarth
double AEarth
semi-major axis of Earth (meters)
Definition: Position.hpp:1062
gnsstk::Position::X
double X() const noexcept
return X coordinate (meters)
Definition: Position.cpp:353
gnsstk::Position::convertSphericalToCartesian
static void convertSphericalToCartesian(const Triple &tpr, Triple &xyz) noexcept
Definition: Position.cpp:1044
gnsstk::Angle::setValue
void setValue(double v, AngleType t)
Definition: Angle.cpp:68
gnsstk::Position::longitude
double longitude() const noexcept
Definition: Position.cpp:432
DebugTrace.hpp
std
Definition: Angle.hpp:142
gnsstk::Position::getIonosphericPiercePoint
Position getIonosphericPiercePoint(const double elev, const double azim, const double ionoht) const noexcept
Definition: Position.cpp:1450
gnsstk::Position::operator!=
bool operator!=(const Position &right) const noexcept
Definition: Position.cpp:235
gnsstk::range
double range(const Position &A, const Position &B)
Definition: Position.cpp:1273
gnsstk::Position
Definition: Position.hpp:136
gnsstk::Position::setGeodetic
Position & setGeodetic(const double lat, const double lon, const double ht, const EllipsoidModel *ell=nullptr)
Definition: Position.cpp:495
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::operator-
SparseMatrix< T > operator-(const SparseMatrix< T > &L, const SparseMatrix< T > &R)
Matrix subtraction: SparseMatrix = SparseMatrix - SparseMatrix.
Definition: SparseMatrix.hpp:1451
DEBUGTRACE_FUNCTION
#define DEBUGTRACE_FUNCTION()
Definition: DebugTrace.hpp:117
gnsstk::Triple::elvAngle
double elvAngle(const Triple &right) const
Definition: Triple.cpp:185
gnsstk::Position::theta
double theta() const noexcept
return spherical coordinate theta in degrees
Definition: Position.cpp:409
gnsstk::Position::operator==
bool operator==(const Position &right) const noexcept
Definition: Position.cpp:221
gnsstk::Position::convertGeodeticToCartesian
static void convertGeodeticToCartesian(const Triple &llh, Triple &xyz, const double A, const double eccSq) noexcept
Definition: Position.cpp:1126
gnsstk::EllipsoidModel
Definition: EllipsoidModel.hpp:56
gnsstk::StringUtils::formattedPrint
std::string formattedPrint(const std::string &fmt, const std::string &pat, const std::string &rep, T to)
Definition: StringUtils.hpp:2020
gnsstk::Position::getRayPosition
Position getRayPosition(double dist, const Position &target) const
Definition: Position.cpp:1604
gnsstk::EllipsoidModel::a
virtual double a() const noexcept=0
gnsstk::Position::getRayPerigee
Position getRayPerigee(const Position &target) const
Definition: Position.cpp:1552
gnsstk::Triple::azAngle
double azAngle(const Triple &right) const
Definition: Triple.cpp:195
gnsstk::Position::elevationGeodetic
double elevationGeodetic(const Position &Target) const
Definition: Position.cpp:1331
gnsstk::Position::convertCartesianToSpherical
static void convertCartesianToSpherical(const Triple &xyz, Triple &tpr) noexcept
Definition: Position.cpp:1058
gnsstk::Position::convertGeocentricToGeodetic
static void convertGeocentricToGeodetic(const Triple &llr, Triple &geodeticllh, const double A, const double eccSq) noexcept
Definition: Position.cpp:1170
gnsstk::Position::elevation
double elevation(const Position &Target) const
Definition: Position.cpp:1308
gnsstk::Position::getSystemName
std::string getSystemName() noexcept
return string giving name of coordinate system
Definition: Position.cpp:63
gnsstk::Position::operator-=
Position & operator-=(const Position &right) noexcept
Definition: Position.cpp:156
gnsstk::Position::convertCartesianToGeocentric
static void convertCartesianToGeocentric(const Triple &xyz, Triple &llr) noexcept
Definition: Position.cpp:1144
gnsstk::Position::eccSquared
double eccSquared
square of ellipsoid eccentricity
Definition: Position.hpp:1065
gnsstk::DEG_TO_RAD
static const double DEG_TO_RAD
Conversion Factor from degrees to radians (units: degrees^-1)
Definition: GNSSconstants.hpp:76
gnsstk::Triple::mag
double mag() const noexcept
Definition: Triple.cpp:129
gnsstk::Position::getCurvPrimeVertical
double getCurvPrimeVertical() const noexcept
Definition: Position.cpp:1503


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:40