|  |  |  | #define _USE_MATH_DEFINES
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							|  |  |  | #include <eigen3/Eigen/Dense>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "coordinates.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | double a = 6378137; // lgtm [cpp/short-global-name]
 | 
					
						
							|  |  |  | double b = 6356752.3142; // lgtm [cpp/short-global-name]
 | 
					
						
							|  |  |  | double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name]
 | 
					
						
							|  |  |  | double e1sq = 6.73949674228 * 0.001;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Geodetic to_degrees(Geodetic geodetic){
 | 
					
						
							|  |  |  |   geodetic.lat = RAD2DEG(geodetic.lat);
 | 
					
						
							|  |  |  |   geodetic.lon = RAD2DEG(geodetic.lon);
 | 
					
						
							|  |  |  |   return geodetic;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Geodetic to_radians(Geodetic geodetic){
 | 
					
						
							|  |  |  |   geodetic.lat = DEG2RAD(geodetic.lat);
 | 
					
						
							|  |  |  |   geodetic.lon = DEG2RAD(geodetic.lon);
 | 
					
						
							|  |  |  |   return geodetic;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ECEF geodetic2ecef(Geodetic g){
 | 
					
						
							|  |  |  |   g = to_radians(g);
 | 
					
						
							|  |  |  |   double xi = sqrt(1.0 - esq * pow(sin(g.lat), 2));
 | 
					
						
							|  |  |  |   double x = (a / xi + g.alt) * cos(g.lat) * cos(g.lon);
 | 
					
						
							|  |  |  |   double y = (a / xi + g.alt) * cos(g.lat) * sin(g.lon);
 | 
					
						
							|  |  |  |   double z = (a / xi * (1.0 - esq) + g.alt) * sin(g.lat);
 | 
					
						
							|  |  |  |   return {x, y, z};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Geodetic ecef2geodetic(ECEF e){
 | 
					
						
							|  |  |  |   // Convert from ECEF to geodetic using Ferrari's methods
 | 
					
						
							|  |  |  |   // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
 | 
					
						
							|  |  |  |   double x = e.x;
 | 
					
						
							|  |  |  |   double y = e.y;
 | 
					
						
							|  |  |  |   double z = e.z;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   double r = sqrt(x * x + y * y);
 | 
					
						
							|  |  |  |   double Esq = a * a - b * b;
 | 
					
						
							|  |  |  |   double F = 54 * b * b * z * z;
 | 
					
						
							|  |  |  |   double G = r * r + (1 - esq) * z * z - esq * Esq;
 | 
					
						
							|  |  |  |   double C = (esq * esq * F * r * r) / (pow(G, 3));
 | 
					
						
							|  |  |  |   double S = cbrt(1 + C + sqrt(C * C + 2 * C));
 | 
					
						
							|  |  |  |   double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
 | 
					
						
							|  |  |  |   double Q = sqrt(1 + 2 * esq * esq * P);
 | 
					
						
							|  |  |  |   double r_0 = -(P * esq * r) / (1 + Q) + sqrt(0.5 * a * a*(1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
 | 
					
						
							|  |  |  |   double U = sqrt(pow((r - esq * r_0), 2) + z * z);
 | 
					
						
							|  |  |  |   double V = sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z);
 | 
					
						
							|  |  |  |   double Z_0 = b * b * z / (a * V);
 | 
					
						
							|  |  |  |   double h = U * (1 - b * b / (a * V));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   double lat = atan((z + e1sq * Z_0) / r);
 | 
					
						
							|  |  |  |   double lon = atan2(y, x);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return to_degrees({lat, lon, h});
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LocalCoord::LocalCoord(Geodetic g, ECEF e){
 | 
					
						
							|  |  |  |   init_ecef <<  e.x, e.y, e.z;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g = to_radians(g);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ned2ecef_matrix <<
 | 
					
						
							|  |  |  |     -sin(g.lat)*cos(g.lon), -sin(g.lon), -cos(g.lat)*cos(g.lon),
 | 
					
						
							|  |  |  |     -sin(g.lat)*sin(g.lon), cos(g.lon), -cos(g.lat)*sin(g.lon),
 | 
					
						
							|  |  |  |     cos(g.lat), 0, -sin(g.lat);
 | 
					
						
							|  |  |  |   ecef2ned_matrix = ned2ecef_matrix.transpose();
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NED LocalCoord::ecef2ned(ECEF e) {
 | 
					
						
							|  |  |  |   Eigen::Vector3d ecef;
 | 
					
						
							|  |  |  |   ecef << e.x, e.y, e.z;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Eigen::Vector3d ned = (ecef2ned_matrix * (ecef - init_ecef));
 | 
					
						
							|  |  |  |   return {ned[0], ned[1], ned[2]};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ECEF LocalCoord::ned2ecef(NED n) {
 | 
					
						
							|  |  |  |   Eigen::Vector3d ned;
 | 
					
						
							|  |  |  |   ned << n.n, n.e, n.d;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Eigen::Vector3d ecef = (ned2ecef_matrix * ned) + init_ecef;
 | 
					
						
							|  |  |  |   return {ecef[0], ecef[1], ecef[2]};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NED LocalCoord::geodetic2ned(Geodetic g) {
 | 
					
						
							|  |  |  |   ECEF e = ::geodetic2ecef(g);
 | 
					
						
							|  |  |  |   return ecef2ned(e);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Geodetic LocalCoord::ned2geodetic(NED n){
 | 
					
						
							|  |  |  |   ECEF e = ned2ecef(n);
 | 
					
						
							|  |  |  |   return ::ecef2geodetic(e);
 | 
					
						
							|  |  |  | }
 |