💿🐜 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.

406 lines
12 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. *
  185. * @return BCI to BCBF transformation.
  186. *
  187. * @see Archinal, B.A., AHearn, M.F., Bowell, E. et al. Report of the IAU Working Group on Cartographic Coordinates and Rotational Elements: 2009. Celest Mech Dyn Astr 109, 101135 (2011). https://doi.org/10.1007/s10569-010-9320-4
  188. */
  189. template <typename T>
  190. math::transformation::se3<T> to_bcbf(T ra, T dec, T w)
  191. {
  192. const math::quaternion<T> r = math::normalize
  193. (
  194. math::quaternion<T>::rotate_z(-math::half_pi<T> - ra) *
  195. math::quaternion<T>::rotate_x(dec - math::half_pi<T>) *
  196. math::quaternion<T>::rotate_z(-w)
  197. );
  198. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  199. }
  200. /**
  201. * Constructs an SE(3) transformation from a BCI frame to a PQW frame.
  202. *
  203. * @param om Right ascension of the ascending node (OMEGA), in radians.
  204. * @param in Orbital inclination (i), in radians.
  205. * @param w Argument of periapsis (omega), in radians.
  206. * @return BCI to PQW transformation.
  207. */
  208. template <typename T>
  209. math::transformation::se3<T> to_pqw(T om, T in, T w)
  210. {
  211. const math::quaternion<T> r = math::normalize
  212. (
  213. math::quaternion<T>::rotate_z(-w) *
  214. math::quaternion<T>::rotate_x(-in) *
  215. math::quaternion<T>::rotate_z(-om)
  216. );
  217. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  218. }
  219. } // namespace bci
  220. /// Body-centered, body-fixed (BCBF) frame.
  221. namespace bcbf {
  222. /**
  223. * Converts BCBF coordinates from spherical to Cartesian.
  224. *
  225. * @param v BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians).
  226. * @return BCBF Cartesian coordinates.
  227. */
  228. template <class T>
  229. math::vector3<T> cartesian(const math::vector3<T>& v)
  230. {
  231. const T x = v[0] * std::cos(v[1]);
  232. return math::vector3<T>
  233. {
  234. x * std::cos(v[2]),
  235. x * std::sin(v[2]),
  236. v[0] * std::sin(v[1]),
  237. };
  238. }
  239. /**
  240. * Converts BCBF coordinates from Cartesian to spherical.
  241. *
  242. * @param v BCBF Cartesian coordinates.
  243. * @return BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians).
  244. */
  245. template <class T>
  246. math::vector3<T> spherical(const math::vector3<T>& v)
  247. {
  248. const T xx_yy = v.x() * v.x() + v.y() * v.y();
  249. return math::vector3<T>
  250. {
  251. std::sqrt(xx_yy + v.z() * v.z()),
  252. std::atan2(v.z(), std::sqrt(xx_yy)),
  253. std::atan2(v.y(), v.x())
  254. };
  255. }
  256. /**
  257. * Constructs an SE(3) transformation from a BCBF frame to a BCI frame.
  258. *
  259. * @param ra Right ascension of the north pole, in radians.
  260. * @param dec Declination of the north pole, in radians.
  261. * @param w Location of the prime meridian, as a rotation about the north pole, in radians.
  262. *
  263. * @return BCBF to BCI transformation.
  264. *
  265. * @see Archinal, B.A., AHearn, M.F., Bowell, E. et al. Report of the IAU Working Group on Cartographic Coordinates and Rotational Elements: 2009. Celest Mech Dyn Astr 109, 101135 (2011). https://doi.org/10.1007/s10569-010-9320-4
  266. */
  267. template <typename T>
  268. math::transformation::se3<T> to_bci(T ra, T dec, T w)
  269. {
  270. const math::quaternion<T> r = math::normalize
  271. (
  272. math::quaternion<T>::rotate_z(w) *
  273. math::quaternion<T>::rotate_x(math::half_pi<T> - dec) *
  274. math::quaternion<T>::rotate_z(ra + math::half_pi<T>)
  275. );
  276. return math::transformation::se3<T>{{T(0), T(0), T(0)}, r};
  277. }
  278. /**
  279. * Constructs an SE(3) transformation from a BCBF frame to an ENU frame.
  280. *
  281. * @param distance Radial distance of the observer from the center of the body.
  282. * @param latitude Latitude of the observer, in radians.
  283. * @param longitude Longitude of the observer, in radians.
  284. * @return BCBF to ENU transformation.
  285. */
  286. template <typename T>
  287. math::transformation::se3<T> to_enu(T distance, T latitude, T longitude)
  288. {
  289. const math::vector3<T> t = {T(0), T(0), -distance};
  290. const math::quaternion<T> r = math::normalize
  291. (
  292. math::quaternion<T>::rotate_x(-math::half_pi<T> + latitude) *
  293. math::quaternion<T>::rotate_z(-longitude - math::half_pi<T>)
  294. );
  295. return math::transformation::se3<T>{t, r};
  296. }
  297. } // namespace bcbf
  298. /// East, North, Up (ENU) horizontal frame.
  299. namespace enu {
  300. /**
  301. * Converts ENU coordinates from spherical to Cartesian.
  302. *
  303. * @param v ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians).
  304. * @return ENU Cartesian coordinates.
  305. */
  306. template <class T>
  307. math::vector3<T> cartesian(const math::vector3<T>& v)
  308. {
  309. const T x = v[0] * std::cos(v[1]);
  310. const T y = math::half_pi<T> - v[2];
  311. return math::vector3<T>
  312. {
  313. x * std::cos(y),
  314. x * std::sin(y),
  315. v[0] * std::sin(v[1]),
  316. };
  317. }
  318. /**
  319. * Converts ENU coordinates from Cartesian to spherical.
  320. *
  321. * @param v ENU Cartesian coordinates.
  322. * @return ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians).
  323. */
  324. template <class T>
  325. math::vector3<T> spherical(const math::vector3<T>& v)
  326. {
  327. const T xx_yy = v.x() * v.x() + v.y() * v.y();
  328. return math::vector3<T>
  329. {
  330. std::sqrt(xx_yy + v.z() * v.z()),
  331. std::atan2(v.z(), std::sqrt(xx_yy)),
  332. math::half_pi<T> - std::atan2(v.y(), v.x())
  333. };
  334. }
  335. /**
  336. * Constructs an SE(3) transformation from an ENU frame to a BCBF frame.
  337. *
  338. * @param distance Radial distance of the observer from the center of the body.
  339. * @param latitude Latitude of the observer, in radians.
  340. * @param longitude Longitude of the observer, in radians.
  341. * @return ENU to BCBF transformation.
  342. */
  343. template <typename T>
  344. math::transformation::se3<T> to_bcbf(T distance, T latitude, T longitude)
  345. {
  346. const math::vector3<T> t = {T(0), T(0), distance};
  347. const math::quaternion<T> r = math::normalize
  348. (
  349. math::quaternion<T>::rotate_z(longitude + math::half_pi<T>) *
  350. math::quaternion<T>::rotate_x(math::half_pi<T> - latitude)
  351. );
  352. return math::transformation::se3<T>{r * t, r};
  353. }
  354. } // namespace enu
  355. } // namespace frame
  356. } // namespace orbit
  357. } // namespace physics
  358. #endif // ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP