0.4.1
Loading...
Searching...
No Matches
Ellipsoid.hpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9/// @file Ellipsoid.hpp
10/// @brief Functions concerning the ellipsoid model
11/// @author T. Topp (topp@ins.uni-stuttgart.de)
12/// @date 2021-11-28
13
14#pragma once
15
16#include <concepts>
18
19namespace NAV
20{
21
22/// @brief r_eS^e The distance of a point on the Earth's surface from the center of the Earth
23/// @param[in] latitude 𝜙 Latitude in [rad]
24/// @param[in] R_E Prime vertical radius of curvature (East/West) in [m]
25/// @param[in] e_squared Square of the first eccentricity of the ellipsoid
26/// @return Geocentric Radius in [m]
27/// @note \cite Groves2013 Groves, ch. 2.4.7, eq. 2.137, p. 71
28template<std::floating_point Scalar>
29[[nodiscard]] Scalar calcGeocentricRadius(const Scalar& latitude, const Scalar& R_E, const Scalar& e_squared = InsConst::WGS84::e_squared)
30{
31 return R_E * std::sqrt(std::pow(std::cos(latitude), 2) + std::pow((1.0 - e_squared) * std::sin(latitude), 2));
32}
33
34/// @brief Calculates the North/South (meridian) earth radius
35/// @param[in] latitude 𝜙 Latitude in [rad]
36/// @param[in] a Semi-major axis
37/// @param[in] e_squared Square of the first eccentricity of the ellipsoid
38/// @return North/South (meridian) earth radius [m]
39/// @note See \cite Groves2013 Groves, ch. 2.4.2, eq. 2.105, p. 59
40/// @note See \cite Titterton2004 Titterton, ch. 3.7.2, eq. 3.83, p. 49
41template<std::floating_point Scalar>
42[[nodiscard]] Scalar calcEarthRadius_N(const Scalar& latitude, const Scalar& a = InsConst::WGS84::a, const Scalar& e_squared = InsConst::WGS84::e_squared)
43{
44 Scalar k = std::sqrt(1 - e_squared * std::pow(std::sin(latitude), 2));
45
46 // North/South (meridian) earth radius [m]
47 return a * (1 - e_squared) / std::pow(k, 3);
48}
49
50/// @brief Calculates the East/West (prime vertical) earth radius
51/// @param[in] latitude 𝜙 Latitude in [rad]
52/// @param[in] a Semi-major axis
53/// @param[in] e_squared Square of the first eccentricity of the ellipsoid
54/// @return East/West (prime vertical) earth radius [m]
55/// @note See \cite Groves2013 Groves, ch. 2.4.2, eq. 2.106, p. 59
56/// @note See \cite Titterton2004 Titterton, ch. 3.7.2, eq. 3.84, p. 49
57template<std::floating_point Scalar>
58[[nodiscard]] Scalar calcEarthRadius_E(const Scalar& latitude, const Scalar& a = InsConst::WGS84::a, const Scalar& e_squared = InsConst::WGS84::e_squared)
59{
60 // East/West (prime vertical) earth radius [m]
61 return a / std::sqrt(1 - e_squared * std::pow(std::sin(latitude), 2));
62}
63
64/// @brief Conversion matrix between cartesian and curvilinear perturbations to the position
65/// @param[in] lla_position Position as Lat Lon Alt in [rad rad m]
66/// @param[in] R_N Meridian radius of curvature in [m]
67/// @param[in] R_E Prime vertical radius of curvature (East/West) [m]
68/// @return T_rn_p A 3x3 matrix
69/// @note See \cite Groves2013 Groves, ch. 2.4.3, eq. 2.119, p. 63
70template<typename Derived>
71[[nodiscard]] Eigen::Matrix3<typename Derived::Scalar> conversionMatrixCartesianCurvilinear(const Eigen::MatrixBase<Derived>& lla_position,
72 const typename Derived::Scalar& R_N, const typename Derived::Scalar& R_E)
73{
74 return Eigen::DiagonalMatrix<typename Derived::Scalar, 3>{ 1.0 / (R_N + lla_position(2)),
75 1.0 / ((R_E + lla_position(2)) * std::cos(lla_position(0))),
76 -1.0 };
77}
78
79/// @brief Measure the distance between two points on a sphere
80/// @param[in] lat1 Latitude of first point in [rad]
81/// @param[in] lon1 Longitude of first point in [rad]
82/// @param[in] lat2 Latitude of second point in [rad]
83/// @param[in] lon2 Longitude of second point in [rad]
84/// @return The distance in [m]
85///
86/// @note See Haversine Formula (https://www.movable-type.co.uk/scripts/latlong.html)
87template<std::floating_point Scalar>
88[[nodiscard]] Scalar calcGreatCircleDistance(Scalar lat1, Scalar lon1, Scalar lat2, Scalar lon2)
89{
90 Scalar R = calcGeocentricRadius(lat1, calcEarthRadius_E(lat1));
91 Scalar dLat = lat2 - lat1;
92 Scalar dLon = lon2 - lon1;
93 Scalar a = std::pow(std::sin(dLat / 2.0), 2) + std::cos(lat1) * std::cos(lat2) * std::pow(std::sin(dLon / 2.0), 2);
94 Scalar c = 2.0 * std::atan2(std::sqrt(a), std::sqrt(1.0 - a));
95 return R * c; // meters
96}
97
98/// @brief Measure the distance between two points over an ellipsoidal-surface
99/// @param[in] lat1 Latitude of first point in [rad]
100/// @param[in] lon1 Longitude of first point in [rad]
101/// @param[in] lat2 Latitude of second point in [rad]
102/// @param[in] lon2 Longitude of second point in [rad]
103/// @return The distance in [m]
104///
105/// @note See Lambert's formula for long lines (https://en.wikipedia.org/wiki/Geographical_distance#Lambert's_formula_for_long_lines)
106template<std::floating_point Scalar>
107[[nodiscard]] Scalar calcGeographicalDistance(Scalar lat1, Scalar lon1, Scalar lat2, Scalar lon2)
108{
109 if (lat1 == lat2 && lon1 == lon2)
110 {
111 return 0;
112 }
113 // First convert the latitudes 𝜙₁,𝜙₂ of the two points to reduced latitudes 𝛽₁,𝛽₂
114 Scalar beta1 = std::atan((1 - InsConst::WGS84::f) * std::tan(lat1));
115 Scalar beta2 = std::atan((1 - InsConst::WGS84::f) * std::tan(lat2));
116
117 // Then calculate the central angle 𝜎 in radians between two points 𝛽₁,𝜆₁ and 𝛽₂,𝜆₂ on a sphere using the
118 // Great-circle distance method (law of cosines or haversine formula), with longitudes 𝜆₁ and 𝜆₂ being the same on the sphere as on the spheroid.
119 Scalar sigma = calcGreatCircleDistance(beta1, lon1, beta2, lon2)
121
122 Scalar P = (beta1 + beta2) / 2;
123 Scalar Q = (beta2 - beta1) / 2;
124
125 Scalar X = (sigma - std::sin(sigma)) * std::pow((std::sin(P) * std::cos(Q)) / std::cos(sigma / 2), 2);
126 Scalar Y = (sigma + std::sin(sigma)) * std::pow((std::cos(P) * std::sin(Q)) / std::sin(sigma / 2), 2);
127
128 return InsConst::WGS84::a * (sigma - InsConst::WGS84::f / 2.0 * (X + Y));
129}
130
131} // namespace NAV
Holds all Constants.
static constexpr double f
Flattening f = (a-b)/a.
Definition Constants.hpp:52
static constexpr double a
Semi-major axis = equatorial radius.
Definition Constants.hpp:50
static constexpr double e_squared
Square of the first eccentricity of the ellipsoid.
Definition Constants.hpp:56
Scalar calcGeographicalDistance(Scalar lat1, Scalar lon1, Scalar lat2, Scalar lon2)
Measure the distance between two points over an ellipsoidal-surface.
Scalar calcEarthRadius_N(const Scalar &latitude, const Scalar &a=InsConst::WGS84::a, const Scalar &e_squared=InsConst::WGS84::e_squared)
Calculates the North/South (meridian) earth radius.
Definition Ellipsoid.hpp:42
Scalar calcGreatCircleDistance(Scalar lat1, Scalar lon1, Scalar lat2, Scalar lon2)
Measure the distance between two points on a sphere.
Definition Ellipsoid.hpp:88
Scalar calcGeocentricRadius(const Scalar &latitude, const Scalar &R_E, const Scalar &e_squared=InsConst::WGS84::e_squared)
r_eS^e The distance of a point on the Earth's surface from the center of the Earth
Definition Ellipsoid.hpp:29
Eigen::Matrix3< typename Derived::Scalar > conversionMatrixCartesianCurvilinear(const Eigen::MatrixBase< Derived > &lla_position, const typename Derived::Scalar &R_N, const typename Derived::Scalar &R_E)
Conversion matrix between cartesian and curvilinear perturbations to the position.
Definition Ellipsoid.hpp:71
Scalar calcEarthRadius_E(const Scalar &latitude, const Scalar &a=InsConst::WGS84::a, const Scalar &e_squared=InsConst::WGS84::e_squared)
Calculates the East/West (prime vertical) earth radius.
Definition Ellipsoid.hpp:58