💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
11 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP
  20. #define ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP
  21. #include "math/se3.hpp"
  22. #include <cmath>
  23. namespace physics {
  24. namespace orbit {
  25. /// Orbital reference frames.
  26. namespace frame {
  27. /// Perifocal (PQW) frame.
  28. namespace pqw {
  29. /**
  30. * Converts PQW coordinates from Cartesian to spherical.
  31. *
  32. * @param v PQW Cartesian coordinates.
  33. * @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians).
  34. */
  35. template <class T>
  36. math::vector3<T> spherical(const math::vector3<T>& v)
  37. {
  38. const T xx_yy = v.x * v.x + v.y * v.y;
  39. return math::vector3<T>
  40. {
  41. std::sqrt(xx_yy + v.z * v.z),
  42. std::atan2(v.z, std::sqrt(xx_yy)),
  43. std::atan2(v.y, v.x)
  44. };
  45. }
  46. /**
  47. * Constructs spherical PQW coordinates from Keplerian orbital elements.
  48. *
  49. * @param ec Eccentricity (e).
  50. * @param a Semimajor axis (a).
  51. * @param ea Eccentric anomaly (E), in radians.
  52. * @param b Semiminor axis (b).
  53. * @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians).
  54. */
  55. template <class T>
  56. math::vector3<T> spherical(T ec, T a, T ea, T b)
  57. {
  58. const T x = a * (std::cos(ea) - ec);
  59. const T y = b * std::sin(ea);
  60. const T d = std::sqrt(x * x + y * y);
  61. const T ta = std::atan2(y, x);
  62. return math::vector3<T>{d, T(0), ta};
  63. }
  64. /**
  65. * Constructs spherical PQW coordinates from Keplerian orbital elements.
  66. *
  67. * @param ec Eccentricity (e).
  68. * @param a Semimajor axis (a).
  69. * @param ea Eccentric anomaly (E), in radians.
  70. * @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians).
  71. */
  72. template <class T>
  73. math::vector3<T> spherical(T ec, T a, T ea)
  74. {
  75. const T b = a * std::sqrt(T(1) - ec * ec);
  76. return spherical<T>(ec, a, ea, b);
  77. }
  78. /**
  79. * Converts PQW coordinates from spherical to Cartesian.
  80. *
  81. * @param PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians).
  82. * @return PQW Cartesian coordinates.
  83. */
  84. template <class T>
  85. math::vector3<T> cartesian(const math::vector3<T>& v)
  86. {
  87. const T x = v[0] * std::cos(v[1]);
  88. return math::vector3<T>
  89. {
  90. x * std::cos(v[2]),
  91. x * std::sin(v[2]),
  92. v[0] * std::sin(v[1]),
  93. };
  94. }
  95. /**
  96. * Constructs Cartesian PQW coordinates from Keplerian orbital elements.
  97. *
  98. * @param ec Eccentricity (e).
  99. * @param a Semimajor axis (a).
  100. * @param ea Eccentric anomaly (E), in radians.
  101. * @param b Semiminor axis (b).
  102. * @return PQW Cartesian coordinates.
  103. */
  104. template <class T>
  105. math::vector3<T> cartesian(T ec, T a, T ea, T b)
  106. {
  107. return cartesian<T>(spherical<T>(ec, a, ea, b));
  108. }
  109. /**
  110. * Constructs Cartesian PQW coordinates from Keplerian orbital elements.
  111. *
  112. * @param ec Eccentricity (e).
  113. * @param a Semimajor axis (a).
  114. * @param ea Eccentric anomaly (E), in radians.
  115. * @return PQW Cartesian coordinates.
  116. */
  117. template <class T>
  118. math::vector3<T> cartesian(T ec, T a, T ea)
  119. {
  120. return cartesian<T>(spherical<T>(ec, a, ea));
  121. }
  122. /**
  123. * Constructs an SE(3) transformation from a PQW frame to a BCI frame.
  124. *
  125. * @param om Right ascension of the ascending node (OMEGA), in radians.
  126. * @param in Orbital inclination (i), in radians.
  127. * @param w Argument of periapsis (omega), in radians.
  128. * @return PQW to BCI transformation.
  129. */
  130. template <typename T>
  131. math::transformation::se3<T> to_bci(T om, T in, T w)
  132. {
  133. const math::quaternion<T> r = math::normalize
  134. (
  135. math::quaternion<T>::rotate_z(om) *
  136. math::quaternion<T>::rotate_x(in) *
  137. math::quaternion<T>::rotate_z(w)
  138. );
  139. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  140. }
  141. } // namespace pqw
  142. /// Body-centered inertial (BCI) frame.
  143. namespace bci {
  144. /**
  145. * Converts BCI coordinates from spherical to Cartesian.
  146. *
  147. * @param v BCI spherical coordinates, in the ISO order of radial distance, declination (radians), and right ascension (radians).
  148. * @return BCI Cartesian coordinates.
  149. */
  150. template <class T>
  151. math::vector3<T> cartesian(const math::vector3<T>& v)
  152. {
  153. const T x = v[0] * std::cos(v[1]);
  154. return math::vector3<T>
  155. {
  156. x * std::cos(v[2]),
  157. x * std::sin(v[2]),
  158. v[0] * std::sin(v[1]),
  159. };
  160. }
  161. /**
  162. * Converts BCI coordinates from Cartesian to spherical.
  163. *
  164. * @param v BCI Cartesian coordinates.
  165. * @return BCI spherical coordinates, in the ISO order of radial distance, declination (radians), and right ascension (radians).
  166. */
  167. template <class T>
  168. math::vector3<T> spherical(const math::vector3<T>& v)
  169. {
  170. const T xx_yy = v.x * v.x + v.y * v.y;
  171. return math::vector3<T>
  172. {
  173. std::sqrt(xx_yy + v.z * v.z),
  174. std::atan2(v.z, std::sqrt(xx_yy)),
  175. std::atan2(v.y, v.x)
  176. };
  177. }
  178. /**
  179. * Constructs an SE(3) transformation from a BCI frame to a BCBF frame.
  180. *
  181. * @param ra Right ascension of the north pole, in radians.
  182. * @param dec Declination of the north pole, in radians.
  183. * @param w Location of the prime meridian, as a rotation about the north pole, in radians.
  184. * @return BCI to BCBF transformation.
  185. */
  186. template <typename T>
  187. math::transformation::se3<T> to_bcbf(T ra, T dec, T w)
  188. {
  189. const math::quaternion<T> r = math::normalize
  190. (
  191. math::quaternion<T>::rotate_z(-math::half_pi<T> - ra) *
  192. math::quaternion<T>::rotate_x(-math::half_pi<T> + dec) *
  193. math::quaternion<T>::rotate_z(-w)
  194. );
  195. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  196. }
  197. /**
  198. * Constructs an SE(3) transformation from a BCI frame to a PQW frame.
  199. *
  200. * @param om Right ascension of the ascending node (OMEGA), in radians.
  201. * @param in Orbital inclination (i), in radians.
  202. * @param w Argument of periapsis (omega), in radians.
  203. * @return BCI to PQW transformation.
  204. */
  205. template <typename T>
  206. math::transformation::se3<T> to_pqw(T om, T in, T w)
  207. {
  208. const math::quaternion<T> r = math::normalize
  209. (
  210. math::quaternion<T>::rotate_z(-w) *
  211. math::quaternion<T>::rotate_x(-in) *
  212. math::quaternion<T>::rotate_z(-om)
  213. );
  214. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  215. }
  216. } // namespace bci
  217. /// Body-centered, body-fixed (BCBF) frame.
  218. namespace bcbf {
  219. /**
  220. * Converts BCBF coordinates from spherical to Cartesian.
  221. *
  222. * @param v BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians).
  223. * @return BCBF Cartesian coordinates.
  224. */
  225. template <class T>
  226. math::vector3<T> cartesian(const math::vector3<T>& v)
  227. {
  228. const T x = v[0] * std::cos(v[1]);
  229. return math::vector3<T>
  230. {
  231. x * std::cos(v[2]),
  232. x * std::sin(v[2]),
  233. v[0] * std::sin(v[1]),
  234. };
  235. }
  236. /**
  237. * Converts BCBF coordinates from Cartesian to spherical.
  238. *
  239. * @param v BCBF Cartesian coordinates.
  240. * @return BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians).
  241. */
  242. template <class T>
  243. math::vector3<T> spherical(const math::vector3<T>& v)
  244. {
  245. const T xx_yy = v.x * v.x + v.y * v.y;
  246. return math::vector3<T>
  247. {
  248. std::sqrt(xx_yy + v.z * v.z),
  249. std::atan2(v.z, std::sqrt(xx_yy)),
  250. std::atan2(v.y, v.x)
  251. };
  252. }
  253. /**
  254. * Constructs an SE(3) transformation from a BCBF frame to a BCI frame.
  255. *
  256. * @param ra Right ascension of the north pole, in radians.
  257. * @param dec Declination of the north pole, in radians.
  258. * @param w Location of the prime meridian, as a rotation about the north pole, in radians.
  259. * @return BCBF to BCI transformation.
  260. */
  261. template <typename T>
  262. math::transformation::se3<T> to_bci(T ra, T dec, T w)
  263. {
  264. const math::quaternion<T> r = math::normalize
  265. (
  266. math::quaternion<T>::rotate_z(w) *
  267. math::quaternion<T>::rotate_x(math::half_pi<T> - dec) *
  268. math::quaternion<T>::rotate_z(math::half_pi<T> + ra)
  269. );
  270. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  271. }
  272. /**
  273. * Constructs an SE(3) transformation from a BCBF frame to an ENU frame.
  274. *
  275. * @param distance Radial distance of the observer from the center of the body.
  276. * @param latitude Latitude of the observer, in radians.
  277. * @param longitude Longitude of the observer, in radians.
  278. * @return BCBF to ENU transformation.
  279. */
  280. template <typename T>
  281. math::transformation::se3<T> to_enu(T distance, T latitude, T longitude)
  282. {
  283. const math::vector3<T> t = {T(0), T(0), -distance};
  284. const math::quaternion<T> r = math::normalize
  285. (
  286. math::quaternion<T>::rotate_x(-math::half_pi<T> + latitude) *
  287. math::quaternion<T>::rotate_z(-longitude - math::half_pi<T>)
  288. );
  289. return math::transformation::se3<T>{t, r};
  290. }
  291. } // namespace bcbf
  292. /// East, North, Up (ENU) horizontal frame.
  293. namespace enu {
  294. /**
  295. * Converts ENU coordinates from spherical to Cartesian.
  296. *
  297. * @param v ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians).
  298. * @return ENU Cartesian coordinates.
  299. */
  300. template <class T>
  301. math::vector3<T> cartesian(const math::vector3<T>& v)
  302. {
  303. const T x = v[0] * std::cos(v[1]);
  304. const T y = math::half_pi<T> - v[2];
  305. return math::vector3<T>
  306. {
  307. x * std::cos(y),
  308. x * std::sin(y),
  309. v[0] * std::sin(v[1]),
  310. };
  311. }
  312. /**
  313. * Converts ENU coordinates from Cartesian to spherical.
  314. *
  315. * @param v ENU Cartesian coordinates.
  316. * @return ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians).
  317. */
  318. template <class T>
  319. math::vector3<T> spherical(const math::vector3<T>& v)
  320. {
  321. const T xx_yy = v.x * v.x + v.y * v.y;
  322. return math::vector3<T>
  323. {
  324. std::sqrt(xx_yy + v.z * v.z),
  325. std::atan2(v.z, std::sqrt(xx_yy)),
  326. math::half_pi<T> - std::atan2(v.y, v.x)
  327. };
  328. }
  329. /**
  330. * Constructs an SE(3) transformation from an ENU frame to a BCBF frame.
  331. *
  332. * @param distance Radial distance of the observer from the center of the body.
  333. * @param latitude Latitude of the observer, in radians.
  334. * @param longitude Longitude of the observer, in radians.
  335. * @return ENU to BCBF transformation.
  336. */
  337. template <typename T>
  338. math::transformation::se3<T> to_bcbf(T distance, T latitude, T longitude)
  339. {
  340. const math::vector3<T> t = {T(0), T(0), distance};
  341. const math::quaternion<T> r = math::normalize
  342. (
  343. math::quaternion<T>::rotate_z(longitude + math::half_pi<T>) *
  344. math::quaternion<T>::rotate_x(math::half_pi<T> - latitude)
  345. );
  346. return math::transformation::se3<T>{r * t, r};
  347. }
  348. } // namespace enu
  349. } // namespace frame
  350. } // namespace orbit
  351. } // namespace physics
  352. #endif // ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP