GAMS  1.4.0
geodetic_conv.h
Go to the documentation of this file.
1 // Original code written by Ethz Asl, see LICENSE file in this directory.
2 // Modified for GAMS by David Kyle, 2018
3 
4 #ifndef GAMS_POSE_GEODETIC_CONV_H_
5 #define GAMS_POSE_GEODETIC_CONV_H_
6 
7 #include <cmath>
8 #include <array>
9 #include "Eigen/Core"
10 
11 namespace gams { namespace pose { namespace geodetic_util {
12 
13 // Geodetic system parameters
14 static constexpr double kSemimajorAxis = 6378137;
15 static constexpr double kSemiminorAxis = 6356752.3142;
16 static constexpr double kFirstEccentricitySquared = 6.69437999014 * 0.001;
17 static constexpr double kSecondEccentricitySquared = 6.73949674228 * 0.001;
18 static constexpr double kFlattening = 1 / 298.257223563;
19 
21 /*
22 template<size_t Rows, size_t Cols>
23 class Matrix
24 {
25 private:
26  std::array<std::array<double, Cols>, Rows> v_;
27 
28 public:
29  double &operator()(size_t x) {
30  static_assert(Rows == 1 || Cols == 1, "Single index access requires"
31  " Rows == 1 or Cols == 1");
32  if (Rows == 1) {
33  return v_[0][x];
34  } else {
35  return v_[x][0];
36  }
37  }
38 
39  const double &operator()(size_t x) const {
40  static_assert(Rows == 1 || Cols == 1, "Single index access requires"
41  " Rows == 1 or Cols == 1");
42  if (Rows == 1) {
43  return v_[0][x];
44  } else {
45  return v_[x][0];
46  }
47  }
48 
49  double &operator()(size_t r, size_t c) {
50  return v_[r][c];
51  }
52 
53  const double &operator()(size_t r, size_t c) const {
54  return v_[r][c];
55  }
56 
57  Matrix<Cols, Rows> transpose() const {
58  Matrix<Cols, Rows> ret;
59  for (size_t r = 0; r < Rows; ++r) {
60  for (size_t c = 0; c < Cols; ++c) {
61  ret(c, r) = (*this)(r, c);
62  }
63  }
64  return ret;
65  }
66 
67  template<size_t ORows, size_t OCols>
68  Matrix<Rows, OCols> operator*(const Matrix<ORows, OCols> &o) const {
69  static_assert(Cols == ORows, "operator *: Left matrix's column count"
70  " must equal right matrix's row count");
71  Matrix<Rows, OCols> ret;
72  for (size_t r = 0; r < Rows; ++r) {
73  for (size_t c = 0; c < OCols; ++c) {
74  double sum = 0;
75  for (size_t x = 0; x < Cols; ++x) {
76  sum += (*this)(r, x) * o(x, c);
77  }
78  ret(r, c) = sum;
79  }
80  }
81  return ret;
82  }
83 };*/
84 
85 using Matrix3 = Eigen::Matrix<double, 3, 3>;
86 using Vector3 = Eigen::Vector3d;
87 
90 {
91  public:
92 
93  GeodeticConverter(const double latitude,
94  const double longitude,
95  const double altitude) :
96  initial_latitude_(deg2Rad(latitude)),
97  initial_longitude_(deg2Rad(longitude)),
98  initial_altitude_(altitude)
99  {
100  // Compute ECEF of NED origin
101  geodetic2Ecef(latitude, longitude, altitude,
103 
104  // Compute ECEF to NED and NED to ECEF matrices
105  double phiP = atan2(initial_ecef_z_,
106  sqrt(pow(initial_ecef_x_, 2) +
107  pow(initial_ecef_y_, 2)));
108 
111  initial_longitude_).transpose();
112  }
113 
114  void getReference(double* latitude, double* longitude, double* altitude) const
115  {
116  *latitude = initial_latitude_;
117  *longitude = initial_longitude_;
118  *altitude = initial_altitude_;
119  }
120 
121  static void geodetic2Ecef(
122  const double latitude, const double longitude, const double altitude,
123  double* x, double* y, double* z)
124  {
125  // Convert geodetic coordinates to ECEF.
126  // http://code.google.com/p/pysatel/source/browse/trunk/coord.py?r=22
127  double lat_rad = deg2Rad(latitude);
128  double lon_rad = deg2Rad(longitude);
129  double xi = sqrt(1 - kFirstEccentricitySquared *
130  sin(lat_rad) * sin(lat_rad));
131  *x = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * cos(lon_rad);
132  *y = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * sin(lon_rad);
133  *z = (kSemimajorAxis / xi *
134  (1 - kFirstEccentricitySquared) + altitude) *
135  sin(lat_rad);
136  }
137 
138  static void ecef2Geodetic(
139  const double x, const double y, const double z,
140  double* latitude, double* longitude, double* altitude)
141  {
142  // Convert ECEF coordinates to geodetic coordinates.
143  // J. Zhu, "Conversion of Earth-centered Earth-fixed coordinates
144  // to geodetic coordinates," IEEE Transactions on Aerospace and
145  // Electronic Systems, vol. 30, pp. 957-961, 1994.
146 
147  double r = sqrt(x * x + y * y);
148  double Esq = kSemimajorAxis * kSemimajorAxis -
150  double F = 54 * kSemiminorAxis * kSemiminorAxis * z * z;
151  double G = r * r + (1 - kFirstEccentricitySquared) * z * z -
154  F * r * r) / pow(G, 3);
155  double S = cbrt(1 + C + sqrt(C * C + 2 * C));
156  double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
157  double Q = sqrt(1 + 2 * kFirstEccentricitySquared *
159  double r_0 = -(P * kFirstEccentricitySquared * r) / (1 + Q)
160  + sqrt(0.5 * kSemimajorAxis * kSemimajorAxis * (1 + 1.0 / Q) -
161  P * (1 - kFirstEccentricitySquared) * z * z /
162  (Q * (1 + Q)) - 0.5 * P * r * r);
163  double U = sqrt(pow((r - kFirstEccentricitySquared * r_0), 2) + z * z);
164  double V = sqrt(pow((r - kFirstEccentricitySquared * r_0), 2) +
165  (1 - kFirstEccentricitySquared) * z * z);
166  double Z_0 = kSemiminorAxis * kSemiminorAxis * z / (kSemimajorAxis * V);
167  *altitude = U * (1 - kSemiminorAxis * kSemiminorAxis / (kSemimajorAxis * V));
168  *latitude = rad2Deg(atan((z + kSecondEccentricitySquared * Z_0) / r));
169  *longitude = rad2Deg(atan2(y, x));
170  }
171 
172  void ecef2Ned(
173  const double x, const double y, const double z,
174  double* north, double* east, double* down) const
175  {
176  // Converts ECEF coordinate position into local-tangent-plane NED.
177  // Coordinates relative to given ECEF coordinate frame.
178 
179  Vector3 vect, ret;
180  vect(0) = x - initial_ecef_x_;
181  vect(1) = y - initial_ecef_y_;
182  vect(2) = z - initial_ecef_z_;
183  ret = ecef_to_ned_matrix_ * vect;
184  *north = ret(0);
185  *east = ret(1);
186  *down = -ret(2);
187  }
188 
189  void ned2Ecef(
190  const double north, const double east, const double down,
191  double* x, double* y, double* z) const
192  {
193  // NED (north/east/down) to ECEF coordinates
194  Vector3 ned, ret;
195  ned(0) = north;
196  ned(1) = east;
197  ned(2) = -down;
198  ret = ned_to_ecef_matrix_ * ned;
199  *x = ret(0) + initial_ecef_x_;
200  *y = ret(1) + initial_ecef_y_;
201  *z = ret(2) + initial_ecef_z_;
202  }
203 
205  const double latitude, const double longitude, const double altitude,
206  double* north, double* east, double* down) const
207  {
208  // Geodetic position to local NED frame
209  double x, y, z;
210  geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
211  ecef2Ned(x, y, z, north, east, down);
212  }
213 
215  const double north, const double east, const double down,
216  double* latitude, double* longitude, double* altitude) const
217  {
218  // Local NED position to geodetic coordinates
219  double x, y, z;
220  ned2Ecef(north, east, down, &x, &y, &z);
221  ecef2Geodetic(x, y, z, latitude, longitude, altitude);
222  }
223 
225  const double latitude, const double longitude, const double altitude,
226  double* east, double* north, double* up) const
227  {
228  // Geodetic position to local ENU frame
229  double x, y, z;
230  geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
231 
232  double aux_north, aux_east, aux_down;
233  ecef2Ned(x, y, z, &aux_north, &aux_east, &aux_down);
234 
235  *east = aux_east;
236  *north = aux_north;
237  *up = -aux_down;
238  }
239 
241  const double east, const double north, const double up,
242  double* latitude, double* longitude, double* altitude) const
243  {
244  // Local ENU position to geodetic coordinates
245 
246  const double aux_north = north;
247  const double aux_east = east;
248  const double aux_down = -up;
249  double x, y, z;
250  ned2Ecef(aux_north, aux_east, aux_down, &x, &y, &z);
251  ecef2Geodetic(x, y, z, latitude, longitude, altitude);
252  }
253 
254  private:
255  inline static Matrix3 nRe(const double lat_radians,
256  const double lon_radians)
257  {
258  const double sLat = sin(lat_radians);
259  const double sLon = sin(lon_radians);
260  const double cLat = cos(lat_radians);
261  const double cLon = cos(lon_radians);
262 
263  Matrix3 ret;
264  ret(0, 0) = -sLat * cLon;
265  ret(0, 1) = -sLat * sLon;
266  ret(0, 2) = cLat;
267  ret(1, 0) = -sLon;
268  ret(1, 1) = cLon;
269  ret(1, 2) = 0.0;
270  ret(2, 0) = cLat * cLon;
271  ret(2, 1) = cLat * sLon;
272  ret(2, 2) = sLat;
273 
274  return ret;
275  }
276 
277  inline static
278  double rad2Deg(const double radians)
279  {
280  return (radians / M_PI) * 180.0;
281  }
282 
283  inline static
284  double deg2Rad(const double degrees)
285  {
286  return (degrees / 180.0) * M_PI;
287  }
288 
292 
296 
299 }; // class GeodeticConverter
300 } // namespace geodetic_util
301 } // namespace pose
302 } // namespace gams
303 
304 #endif // GEODETIC_CONVERTER_H_
Helper class for translating between LLA, ECEF, and NED coordinates.
Definition: geodetic_conv.h:90
void geodetic2Enu(const double latitude, const double longitude, const double altitude, double *east, double *north, double *up) const
static void ecef2Geodetic(const double x, const double y, const double z, double *latitude, double *longitude, double *altitude)
void ned2Geodetic(const double north, const double east, const double down, double *latitude, double *longitude, double *altitude) const
void geodetic2Ned(const double latitude, const double longitude, const double altitude, double *north, double *east, double *down) const
static double deg2Rad(const double degrees)
GeodeticConverter(const double latitude, const double longitude, const double altitude)
Definition: geodetic_conv.h:93
static Matrix3 nRe(const double lat_radians, const double lon_radians)
void enu2Geodetic(const double east, const double north, const double up, double *latitude, double *longitude, double *altitude) const
static double rad2Deg(const double radians)
static void geodetic2Ecef(const double latitude, const double longitude, const double altitude, double *x, double *y, double *z)
void getReference(double *latitude, double *longitude, double *altitude) const
void ned2Ecef(const double north, const double east, const double down, double *x, double *y, double *z) const
void ecef2Ned(const double x, const double y, const double z, double *north, double *east, double *down) const
Eigen::Vector3d Vector3
Definition: geodetic_conv.h:86
static constexpr double kSecondEccentricitySquared
Definition: geodetic_conv.h:17
static constexpr double kFirstEccentricitySquared
Definition: geodetic_conv.h:16
static constexpr double kSemimajorAxis
Definition: geodetic_conv.h:14
static constexpr double kSemiminorAxis
Definition: geodetic_conv.h:15
static constexpr double kFlattening
Definition: geodetic_conv.h:18
Eigen::Matrix< double, 3, 3 > Matrix3
Minimal implementation of a Matrix for internal use.
Definition: geodetic_conv.h:85
static const detail::radians_t radians
Radians unit flag; see Euler constructor.
Definition: AngleUnits.h:87
static const detail::degrees_t degrees
Degres unit flag; see Euler constructor.
Definition: AngleUnits.h:90
Contains all GAMS-related tools, classes and code.