Astro  0.0.0
A C++ library for space dynamics
Loading...
Searching...
No Matches
OrbitalElements.hxx
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The Astro project is distributed under the GNU GPLv3. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * e-mail: davide.stocco@unitn.it e-mail: enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef ASTRO_ORBITAL_ELEMENTS_HXX
14#define ASTRO_ORBITAL_ELEMENTS_HXX
15
16namespace Astro
17{
19 using Factor = enum class Factor : Integer {
20 POSIGRADE = 1, UNDEFINED = 0, RETROGRADE = -1
21 };
22
24 using Type = enum class Type : Integer {
25 UNDEFINED = 0, HYPERBOLIC = 1, ELLIPTIC = 2, PARABOLIC = 3
26 };
27
34 {
35
36 /*\
37 | ____ _ _
38 | / ___|__ _ _ __| |_ ___ ___(_) __ _ _ __
39 | | | / _` | '__| __/ _ \/ __| |/ _` | '_ \
40 | | |__| (_| | | | || __/\__ \ | (_| | | | |
41 | \____\__,_|_| \__\___||___/_|\__,_|_| |_|
42 |
43 \*/
44
55 struct Cartesian
56 {
59
64
70 Cartesian(Vector3 const &t_r, Vector3 const &t_v) : r(t_r), v(t_v) {}
71
81 Cartesian(Real r_x, Real r_y, Real r_z, Real v_x, Real v_y, Real v_z) :
82 r(r_x, r_y, r_z), v(v_x, v_y, v_z) {}
83
87 Cartesian(Cartesian const &) = default;
88
92 Cartesian(Cartesian &&) = default;
93
97 Cartesian & operator=(const Cartesian &) = default;
98
103
108 std::string info() const {
109 std::ostringstream os;
110 os <<
111 "r = " << this->r.transpose() << " (UA)" << std::endl <<
112 "v = " << this->v.transpose() << " (UA/day)" << std::endl;
113 return os.str();
114 }
115
120 void info(std::ostream & os) {os << this->info();}
121
125 void reset() {
126 this->r = NAN_VEC3;
127 this->v = NAN_VEC3;
128 }
129
133 bool sanity_check() const {
134 #define CMD "Astro::OrbitalElements::Cartesian::sanity_check(...) "
135
136 if (!(this->r.allFinite())) {
137 ASTRO_WARNING(CMD "invalid position vector detected.");
138 return false;
139 }
140 if (!(this->v.allFinite())) {
141 ASTRO_WARNING(CMD "invalid velocity vector detected.");
142 return false;
143 }
144 return true;
145
146 #undef CMD
147 }
148
153 Vector3 h() const {return this->r.cross(this->v);}
154
162 Real e(Real mu) const
163 {
164 return ((this->v.cross(this->h()) / mu) - (this->r / this->r.norm())).norm();
165 }
166
167 }; // struct Cartesian
168
169 /*\
170 | _ __ _ _
171 | | |/ /___ _ __ | | ___ _ __(_) __ _ _ __
172 | | ' // _ \ '_ \| |/ _ \ '__| |/ _` | '_ \
173 | | . \ __/ |_) | | __/ | | | (_| | | | |
174 | |_|\_\___| .__/|_|\___|_| |_|\__,_|_| |_|
175 | |_|
176 \*/
177
193 {
199
204
213 Keplerian(Real t_a, Real t_e, Real t_i, Real t_Omega, Real t_omega)
214 : a(t_a), e(t_e), i(t_i), Omega(t_Omega), omega(t_omega)
215 {}
216
220 Keplerian(Keplerian const &) = default;
221
225 Keplerian(Keplerian &&) = default;
226
230 Keplerian & operator=(const Keplerian &) = default;
231
236
241 std::string info() const {
242 std::ostringstream os;
243 os <<
244 "a : semi-major axis = " << this->a << " (UA)" << std::endl <<
245 "e : eccentricity = " << this->e << " (-)" << std::endl <<
246 "i : inclination = " << this->i << " (rad) = " << rad_to_deg(this->i) << " (deg)" << std::endl <<
247 "Ω : right ascension … = " << this->Omega << " (rad) = " << rad_to_deg(this->Omega) << " (deg)" << std::endl <<
248 "ω : arg. of periapsis = " << this->omega << " (rad) = " << rad_to_deg(this->omega) << " (deg)" << std::endl;
249 return os.str();
250 }
251
256 void info(std::ostream & os) {os << this->info();}
257
261 void reset() {
262 this->a = QUIET_NAN;
263 this->e = QUIET_NAN;
264 this->i = QUIET_NAN;
265 this->Omega = QUIET_NAN;
266 this->omega = QUIET_NAN;
267 }
268
276 bool sanity_check() const
277 {
278 #define CMD "Astro::OrbitalElements::Keplerian::sanity_check(...) "
279
280 if (!std::isfinite(this->a) && this->a > 0.0) {
281 ASTRO_WARNING(CMD "invalid semi-major axis, a = " << this->a << ".");
282 return false;
283 }
284 if (!std::isfinite(this->e) && this->e > 0.0 && this->e < 1.0) {
285 ASTRO_WARNING(CMD "invalid eccentricity, e = " << this->e << ".");
286 return false;
287 }
288 if (!std::isfinite(this->i)) {
289 ASTRO_WARNING(CMD "invalid inclination, i = " << this->i << ".");
290 return false;
291 }
292 if (!std::isfinite(this->Omega)) {
293 ASTRO_WARNING(CMD "invalid right ascension of the ascending node, Ω = " << this->Omega << ".");
294 return false;
295 }
296 if (!std::isfinite(this->omega)) {
297 ASTRO_WARNING(CMD "invalid argument of periapsis, ω = " << this->omega << ".");
298 return false;
299 }
300 ASTRO_ASSERT_WARNING(this->is_nonsingular(), CMD "singular orbit detected.");
301 return true;
302
303 #undef CMD
304 }
305
313 bool is_singular(Real tol_i = EPSILON_LOW, Real tol_e = EPSILON_LOW) const
314 {
315 #define CMD "Astro::OrbitalElements::Keplerian::is_singular(...) "
316
317 Real i{angle_in_range(this->i)};
318 if (i < PI + tol_i && i > PI - tol_i) {
319 ASTRO_WARNING(CMD "singular inclination detected.");
320 return true;
321 }
322 if (this->e > 1.0 - tol_e) {
323 ASTRO_WARNING(CMD "singular eccentricity detected.");
324 return true;
325 }
326 return false;
327
328 #undef CMD
329 }
330
338 bool is_nonsingular(Real tol_i = EPSILON_LOW, Real tol_e = EPSILON_LOW) const
339 {
340 return !this->is_singular(tol_i, tol_e);
341 }
342
347 Real u() const {return this->omega + this->Omega;}
348
353 Real p() const {return this->a * (1.0 - this->e * this->e);}
354
355 }; // struct Keplerian
356
357 /*\
358 | _____ _ _ _ _
359 | | ____|__ _ _ _(_)_ __ ___ ___| |_(_) __ _| |
360 | | _| / _` | | | | | '_ \ / _ \ / __| __| |/ _` | |
361 | | |__| (_| | |_| | | | | | (_) | (__| |_| | (_| | |
362 | |_____\__, |\__,_|_|_| |_|\___/ \___|\__|_|\__,_|_|
363 | |_|
364 \*/
365
382 {
388
389 public:
394
403 Equinoctial(Real t_p, Real t_f, Real t_g, Real t_h, Real t_k)
404 : p(t_p), f(t_f), g(t_g), h(t_h), k(t_k) {}
405
409 Equinoctial(Equinoctial const &) = default;
410
415
419 Equinoctial & operator=(const Equinoctial &) = default;
420
425
430 std::string info() const {
431 std::ostringstream os;
432 os <<
433 "p : semi-latus rectum = " << this->p << " (UA)" << std::endl <<
434 "f : x-axis ecc. vector = " << this->f << " (-)" << std::endl <<
435 "g : y-axis ecc. vector = " << this->g << " (-)" << std::endl <<
436 "h : x-axis node vector = " << this->h << " (-)" << std::endl <<
437 "k : y-axis node vector = " << this->k << " (-)" << std::endl;
438 return os.str();
439 }
440
445 void info(std::ostream & os) {os << this->info();}
446
450 void reset() {
451 this->p = QUIET_NAN;
452 this->f = QUIET_NAN;
453 this->g = QUIET_NAN;
454 this->h = QUIET_NAN;
455 this->k = QUIET_NAN;
456 }
457
462 bool sanity_check() const
463 {
464 #define CMD "Astro::OrbitalElements::Keplerian::sanity_check(...) "
465
466 if (!std::isfinite(this->p) && this->p > 0.0) {
467 ASTRO_WARNING(CMD "invalid semi-latus rectum, p = " << this->p << ".");
468 return false;
469 }
470 if (!std::isfinite(this->f)) {
471 ASTRO_WARNING(CMD "invalid x-axis component of the eccentricity vector, f = " << this->f << ".");
472 return false;
473 }
474 if (!std::isfinite(this->g)) {
475 ASTRO_WARNING(CMD "invalid y-axis component of the eccentricity vector, g = " << this->g << ".");
476 return false;
477 }
478 if (!std::isfinite(this->h)) {
479 ASTRO_WARNING(CMD "invalid x-axis component of the node vector, h = " << this->h << ".");
480 return false;
481 }
482 if (!std::isfinite(this->k)) {
483 ASTRO_WARNING(CMD "invalid y-axis component of the node vector, k = " << this->k << ".");
484 return false;
485 }
486
487 // Check if it is singular
488 ASTRO_ASSERT_WARNING(this->is_nonsingular(), CMD "singular orbit detected.");
489
490 return true;
491
492 #undef CMD
493 }
494
501 bool is_singular(Real tol_i = EPSILON_LOW) const
502 {
503 #define CMD "Astro::OrbitalElements::Keplerian::is_singular(...) "
504
505 Real i{angle_in_range(this->i())};
506 if (i < PI + tol_i && i > PI - tol_i) {
507 ASTRO_WARNING(CMD "singular inclination detected.");
508 return true;
509 }
510 return false;
511
512 #undef CMD
513 }
514
520 bool is_nonsingular(Real tol_i = EPSILON_LOW) const
521 {
522 return !this->is_singular(tol_i);
523 }
524
531 Real u(Real L) const
532 {
533 Real s_L{std::sin(L)}, c_L{std::cos(L)};
534 return std::atan2(this->h*s_L - this->k*c_L, this->h*c_L + this->k*s_L);
535 }
536
541 Real a() const {return this->p / (1.0 - this->f*this->f - this->g*this->g);}
542
547 Real e() const {return std::sqrt(this->f*this->f + this->g*this->g);}
548
553 Real i() const
554 {
555 Real h2{this->h * this->h}, k2{this->k * this->k};
556 return std::atan2(2.0*std::sqrt(h2 + k2), 1.0 - h2 - k2);
557 }
558
563 Real omega() const
564 {
565 return std::atan2(
566 this->g*this->h - this->f*this->k,
567 this->f*this->h + this->g*this->k
568 );
569 }
570
575 Real Omega() const {return std::atan2(this->k, this->h);}
576
577 }; // struct Equinoctial
578
579
580 /*\
581 | ___ _ _ _
582 | / _ \ _ _ __ _| |_ ___ _ __ _ __ (_) ___ _ __ (_) ___
583 | | | | | | | |/ _` | __/ _ \ '__| '_ \| |/ _ \| '_ \| |/ __|
584 | | |_| | |_| | (_| | || __/ | | | | | | (_) | | | | | (__
585 | \__\_\\__,_|\__,_|\__\___|_| |_| |_|_|\___/|_| |_|_|\___|
586 |
587 \*/
588
600 {
602
607
612 Quaternionic(Quaternion const &t_q) : q(t_q) {}
613
621 Quaternionic(Real t_q_1, Real t_q_2, Real t_q_3, Real t_q_4)
622 : q(t_q_1, t_q_2, t_q_3, t_q_4) {}
623
627 Quaternionic(Quaternionic const &) = default;
628
633
637 Quaternionic & operator=(const Quaternionic &) = default;
638
643
647 Rotation r;
648 r << 1.0 - 2.0*(q.y()*q.y() + q.z()*q.z()),
649 2.0*(q.x()*q.y() - q.z()*q.w()),
650 2.0*(q.x()*q.z() + q.y()*q.w()),
651 2.0*(q.x()*q.y() + q.z()*q.w()),
652 1.0 - 2.0*(q.x()*q.x() + q.z()*q.z()),
653 2.0*(q.y()*q.z() - q.x()*q.w()),
654 2.0*(q.x()*q.z() - q.y()*q.w()),
655 2.0*(q.y()*q.z() + q.x()*q.w()),
656 1.0 - 2.0*(q.x()*q.x() + q.y()*q.y());
657 return r;
658 }
659
664 std::string info() const {
665 std::ostringstream os;
666 os <<
667 "q¹ : 1st parameter = " << this->q.x() << " (-)" << std::endl <<
668 "q² : 2nd parameter = " << this->q.y() << " (-)" << std::endl <<
669 "q³ : 3rd parameter = " << this->q.z() << " (-)" << std::endl <<
670 "q⁴ : 4th parameter = " << this->q.w() << " (-)" << std::endl;
671 return os.str();
672 }
673
678 void info(std::ostream & os) {os << this->info();}
679
683 void reset() {this->q = NAN_VEC4;}
684
689 bool sanity_check() const
690 {
691 #define CMD "Astro::OrbitalElements::Quaternionic::sanity_check(...) "
692
693 if (!(std::isfinite(this->q.x()) && std::isfinite(this->q.y()) &&
694 std::isfinite(this->q.z()) && std::isfinite(this->q.w()))) {
695 ASTRO_WARNING(CMD "invalid quaternionic orbital elements.");
696 return false;
697 }
698 return true;
699
700 #undef CMD
701 }
702
703 }; // struct Quaternionic
704
717 Real nu_to_M(Real nu, Keplerian const & kepl)
718 {
719 Real e{kepl.e};
720 Real beta{(1.0 + std::sqrt(1.0 - e*e)) / e};
721 return nu - 2.0 * std::atan(std::sin(nu) / (beta + std::cos(nu))) -
722 (e * std::sqrt(1.0 - e*e) * std::sin(nu)) / (1.0 + e * std::cos(nu));
723 }
724
737 Real nu_to_E(Real nu, Keplerian const & kepl)
738 {
739 Real beta{(1.0 + std::sqrt(1.0 - kepl.e*kepl.e)) / kepl.e};
740 return nu - 2.0 * std::atan(std::sin(nu) / (beta + std::cos(nu)));
741 }
742
751 Real nu_to_L(Real nu, Keplerian const & kepl, Factor I)
752 {
753 return nu + kepl.omega + kepl.Omega*static_cast<Real>(I);
754 }
755
764 Real M_to_E(Real M, Keplerian const & kepl)
765 {
766 #define CMD "Astro::OrbitalElements::Anomaly::M_to_E(...): "
767
768 // Clamp the mean anomaly in the range [0, 2\pi]
769 M = angle_in_range(M);
770
771 // Solve Kepler equation through a basic Newton method
772 Real dE{0.0}, E{M}, e{kepl.e};
773 for (Integer k{0}; k < 100; ++k)
774 {
775 dE = (E - e * std::sin(E) - M) / (1.0 - e * std::cos(E));
776 // Saturate if steps are too largex
777 E -= std::max(std::min(dE, 0.1), -0.1);;
778 // Break if the error is small enough
779 if (std::abs(dE) < EPSILON_HIGH || std::abs(E) < EPSILON_HIGH) {break;}
780 }
781
782 ASTRO_ASSERT(std::abs(dE) < EPSILON_HIGH, CMD "convergence not reached: E = " << E <<
783 ", dE = " << dE << ", M = " << M << ", e = " << e << ".");
784
785 return E;
786
787 #undef CMD
788 }
789
800 Real M_to_H(Real M, Keplerian const & kepl)
801 {
802
803 #define CMD "Astro::OrbitalElements::Anomaly::M_to_H(...): "
804
805 // Solve Kepler equation through a basic Newton method
806 Real e{kepl.e}, abs_M{M > 0 ? M : -M};
807 Real dH{0.0}, H{5.0*e-2.5 > abs_M ? std::pow(6.0*abs_M/e, 1.0/3.0) : std::log(2.0*abs_M/e)};
808 for (Integer k{0}; k < 100; ++k)
809 {
810 dH = (e * std::sinh(H) - H - abs_M) / (e * std::cosh(H) - 1.0);
811 H -= dH;
812 // Break if the error is small enough
813 if (std::abs(dH) < EPSILON_HIGH || std::abs(H) < EPSILON_HIGH) {break;}
814 }
815
816 ASTRO_ASSERT(std::abs(dH) < EPSILON_HIGH, CMD "convergence not reached: H = " << H <<
817 ", dH = " << dH << ", M = " << M << ", e = " << e << ".");
818
819 return H > 0 ? H : -H; // Return the positive value
820
821 #undef CMD
822 }
823
833 {
834 return M + kepl.omega + kepl.Omega*static_cast<Real>(I);
835 }
836
849 Real E_to_nu(Real E, Keplerian const & kepl)
850 {
851 Real beta{(1.0 + std::sqrt(1.0 - kepl.e*kepl.e)) / kepl.e};
852 return E + 2.0 * std::atan(std::sin(E) / (beta - std::cos(E)));
853 }
854
862 Real E_to_M(Real E, Keplerian const & kepl) {return E - kepl.e * std::sin(E);}
863
874 Real H_to_nu(Real H, Keplerian const & kepl)
875 {
876 return 2.0*std::atan(std::sqrt((kepl.e+1.0)/(kepl.e-1.0)) * std::tanh(H/2.0));
877 }
878
886 Real H_to_M(Real H, Keplerian const & kepl) {return kepl.e * std::sinh(H) - H;}
887
896 Real L_to_nu(Real L, Keplerian const & kepl, Factor I)
897 {
898 return L - kepl.omega - kepl.Omega*static_cast<Real>(I);
899 }
900
909 Real L_to_lambda(Real L, Real nu, Real M) {return L - nu + M;}
910
919 Real lambda_to_M(Real lambda, Keplerian const & kepl, Factor I)
920 {
921 return lambda - kepl.omega - static_cast<Real>(I)*kepl.Omega;
922 }
923
932 Real lambda_to_L(Real lambda, Real nu, Real M) {return lambda + nu - M;}
933
934 /*\
935 | _ _
936 | / \ _ __ ___ _ __ ___ __ _| |_ _
937 | / _ \ | '_ \ / _ \| '_ ` _ \ / _` | | | | |
938 | / ___ \| | | | (_) | | | | | | (_| | | |_| |
939 | /_/ \_\_| |_|\___/|_| |_| |_|\__,_|_|\__, |
940 | |___/
941 \*/
942
954 struct Anomaly
955 {
962
967
971 Anomaly(Anomaly const &) = default;
972
976 Anomaly(Anomaly &&) = default;
977
981 Anomaly & operator=(const Anomaly &) = default;
982
986 Anomaly & operator=(Anomaly &&) = default;
987
994 void set_nu(Real nu, Keplerian const & kepl, Factor I)
995 {
996 kepl.sanity_check();
997 this->nu = nu;
998 this->M = nu_to_M(nu, kepl);
999 this->E = nu_to_E(nu, kepl);
1000 this->L = nu_to_L(nu, kepl, I);
1001 this->lambda = M_to_lambda(this->M, kepl, I);
1002 this->H = M_to_H(this->M, kepl);
1003 }
1004
1005
1012 void set_M(Real t_M, Keplerian const & kepl, Factor I)
1013 {
1014 kepl.sanity_check();
1015 this->E = M_to_E(t_M, kepl);
1016 this->nu = E_to_nu(this->E, kepl);
1017 this->M = t_M;
1018 this->L = nu_to_L(this->nu, kepl, I);
1019 this->lambda = M_to_lambda(this->M, kepl, I);
1020 this->H = M_to_H(t_M, kepl);
1021 }
1022
1035 void set_E(Real t_E, Keplerian const & kepl, Factor I)
1036 {
1037 kepl.sanity_check();
1038 this->nu = E_to_nu(t_E, kepl);
1039 this->M = E_to_M(t_E, kepl);
1040 this->E = t_E;
1041 this->L = nu_to_L(this->nu, kepl, I);
1042 this->lambda = M_to_lambda(this->M, kepl, I);
1043 this->H = M_to_H(this->M, kepl);
1044 }
1045
1055 void set_L(Real t_L, Keplerian const & kepl, Factor I)
1056 {
1057 #define CMD "Astro::OrbitalElements::Anomaly::L(...): "
1058
1059 this->set_nu(L_to_nu(t_L, kepl, I) , kepl, I);
1060
1061 ASTRO_ASSERT(std::abs(this->L - t_L) < EPSILON_HIGH,
1062 CMD "conversion error, L = " << t_L << " ≠ " << this->L << ".");
1063
1064 #undef CMD
1065 }
1066
1076 void set_lambda(Real t_lambda, Keplerian const & kepl, Factor I)
1077 {
1078 #define CMD "Astro::OrbitalElements::Anomaly::lambda(...): "
1079
1080 this->set_M(lambda_to_M(t_lambda, kepl, I), kepl, I);
1081
1082 ASTRO_ASSERT(std::abs(this->lambda - t_lambda) < EPSILON_HIGH,
1083 CMD "conversion error, lambda = " << t_lambda << " ≠ " << this->lambda << ".");
1084
1085 #undef CMD
1086 }
1087
1097 void set_H(Real t_H, Keplerian const & kepl, Factor I)
1098 {
1099 #define CMD "Astro::OrbitalElements::Anomaly::H(...): "
1100
1101 this->set_nu(H_to_nu(t_H, kepl), kepl, I);
1102
1103 ASTRO_ASSERT(std::abs(this->H - t_H) < EPSILON_HIGH,
1104 CMD "conversion error, H = " << t_H << " ≠ " << this->H << ".");
1105
1106 #undef CMD
1107 }
1108
1109
1114 std::string info() const {
1115 std::ostringstream os;
1116 os <<
1117 "v : true anomaly = " << this->nu << " (rad) = " << rad_to_deg(this->nu) << " (deg)" << std::endl <<
1118 "M : mean anomaly = " << this->M << " (rad) = " << rad_to_deg(this->M) << " (deg)" << std::endl <<
1119 "E : eccentric anomaly = " << this->E << " (rad) = " << rad_to_deg(this->E) << " (deg)" << std::endl <<
1120 "L : true longitude = " << this->L << " (rad) = " << rad_to_deg(this->L) << " (deg)" << std::endl <<
1121 "λ : mean longitude = " << this->lambda << " (rad) = " << rad_to_deg(this->lambda) << " (deg)" << std::endl <<
1122 "H : hyperbolic anomaly = " << this->H << " (rad) = " << rad_to_deg(this->H) << " (deg)" << std::endl;
1123 return os.str();
1124 }
1125
1130 void info(std::ostream & os) {os << this->info();}
1131
1135 void reset()
1136 {
1137 this->nu = QUIET_NAN;
1138 this->M = QUIET_NAN;
1139 this->E = QUIET_NAN;
1140 this->L = QUIET_NAN;
1141 this->lambda = QUIET_NAN;
1142 this->H = QUIET_NAN;
1143 }
1144
1149 bool sanity_check() const
1150 {
1151 #define CMD "Astro::OrbitalElements::Anomaly::sanity_check(...) "
1152
1153 if (!(std::isfinite(this->nu))) {
1154 ASTRO_ERROR(CMD "invalid true anomaly.");
1155 return false;
1156 }
1157 if (!(std::isfinite(this->M))) {
1158 ASTRO_ERROR(CMD "invalid mean anomaly.");
1159 return false;
1160 }
1161 if (!(std::isfinite(this->E))) {
1162 ASTRO_ERROR(CMD "invalid eccentric anomaly.");
1163 return false;
1164 }
1165 if (!(std::isfinite(this->L))) {
1166 ASTRO_ERROR(CMD "invalid true longitude.");
1167 return false;
1168 }
1169 if (!(std::isfinite(this->lambda))) {
1170 ASTRO_ERROR(CMD "invalid mean longitude.");
1171 return false;
1172 }
1173 // CHECK: if (!(std::isfinite(this->H))) {
1174 // CHECK: ASTRO_ERROR(CMD "invalid hyperbolic anomaly.");
1175 // CHECK: return false;
1176 // CHECK: }
1177 return true;
1178
1179 #undef CMD
1180 }
1181
1182 }; // struct Anomaly
1183
1190 void cartesian_to_keplerian(Cartesian const & cart, Real mu, Keplerian & kepl)
1191 {
1192 #define CMD "Astro::OrbitalElements::cartesian_to_keplerian(...): "
1193
1194 // Reset the keplerian orbital elements
1195 kepl.reset();
1196
1197 // Compute the orbital momentum vector
1198 Vector3 h{cart.h()};
1199
1200 // Compute the eccentricity vector
1201 Real r_norm{cart.r.norm()};
1202 Vector3 e_vec{cart.v.cross(h)/mu - cart.r/r_norm};
1203
1204 // Determine the vector pointing towards the ascending node
1205 Vector3 n{Vector3::UnitZ().cross(h)};
1206
1207 ASTRO_ASSERT(std::abs(h.z()) > EPSILON_MEDIUM,
1208 CMD "conversion error h = " << h << " ≠ 0.");
1209
1210 // Compute the eccentricity
1211 Real e{e_vec.norm()};
1212
1213 // Compute the true anomaly
1214 Real e_dot_r{e_vec.transpose()*cart.r};
1215 Real nu{std::acos(e_dot_r / (e * r_norm))};
1216 if (cart.r.transpose()*cart.v < 0.0) {nu = 2.0*PI - nu;}
1217
1218 // Compute the inclination
1219 Real i{std::acos(h.z() / h.norm())};
1220
1221 // Compute the longitude of the ascending node
1222 Real n_norm{n.norm()};
1223 Real Omega{std::acos(n.x() / n_norm)};
1224 if (n.y() < 0.0) {Omega = 2.0*PI - Omega;}
1225
1226 // Compute the argument of the periapsis
1227 Real n_dot_e_vec{n.transpose()*e_vec};
1228 Real omega{std::acos(n_dot_e_vec / (n_norm * e))};
1229 if (e_vec.z() < 0.0) {omega = 2.0*PI - omega;}
1230
1231 // Compute the semi-major axis
1232 Real a{1.0 / (2.0 / r_norm - cart.v.squaredNorm() / mu)};
1233
1234 // Assign the keplerian orbital elements
1235 kepl.a = a;
1236 kepl.e = e;
1237 kepl.i = i;
1238 kepl.Omega = Omega;
1239 kepl.omega = omega;
1240
1241 ASTRO_ASSERT(kepl.sanity_check(), CMD "conversion error.");
1242
1243 #undef CMD
1244 }
1245
1253 void keplerian_to_cartesian(Keplerian const & kepl, Anomaly const & anom, Real mu, Cartesian & cart)
1254 {
1255 #define CMD "Astro::OrbitalElements::keplerian_to_cartesian(...): "
1256
1257 // Reset the cartesian state vectors
1258 cart.reset();
1259
1260 // Compute the distance to the central body
1261 Real r_c{kepl.a * (1.0 - kepl.e*std::cos(anom.E))};
1262
1263 // Obtain the position and velocity vector r_of and v_of in the orbital frame
1264 Vector2 r_of(
1265 r_c * std::cos(anom.nu),
1266 r_c * std::sin(anom.nu)
1267 // 0.0 third component
1268 );
1269 Vector2 v_of(
1270 -std::sin(anom.E),
1271 std::sqrt(1.0 - kepl.e*kepl.e) * std::cos(anom.E)
1272 // 0.0 third componen
1273 );
1274 v_of *= std::sqrt(mu / kepl.a);
1275
1276 // Compute the position and velocity vectors in the inertial frame
1277 Real c_Omega{std::cos(kepl.Omega)}, s_Omega{std::sin(kepl.Omega)};
1278 Real c_omega{std::cos(kepl.omega)}, s_omega{std::sin(kepl.omega)};
1279 Real c_i{std::cos(kepl.i)}, s_i{std::sin(kepl.i)};
1280 Vector3 r(
1281 r_of.x()*(c_Omega*c_omega - s_Omega*s_omega*c_i) - r_of.y()*(c_Omega*s_omega + s_Omega*c_omega*c_i),
1282 r_of.x()*(s_Omega*c_omega + c_Omega*s_omega*c_i) - r_of.y()*(s_Omega*s_omega - c_Omega*c_omega*c_i),
1283 r_of.x()*(s_omega*s_i) + r_of.y()*(c_omega*s_i)
1284 );
1285 cart.r = r;
1286 Vector3 v(
1287 v_of.x()*(c_Omega*c_omega - s_Omega*s_omega*c_i) - v_of.y()*(c_Omega*s_omega + s_Omega*c_omega*c_i),
1288 v_of.x()*(s_Omega*c_omega + c_Omega*s_omega*c_i) - v_of.y()*(s_Omega*s_omega - c_Omega*c_omega*c_i),
1289 v_of.x()*(s_omega*s_i) + v_of.y()*(c_omega*s_i)
1290 );
1291 cart.v = v;
1292
1293 ASTRO_ASSERT(cart.sanity_check(), CMD "conversion error.");
1294
1295 #undef CMD
1296 }
1297
1305 void equinoctial_to_cartesian(Equinoctial const & equi, Anomaly const & anom, Real mu, Cartesian & cart)
1306 {
1307 #define CMD "Astro::OrbitalElements::equinoctial_to_cartesian(...): "
1308
1309 // Reset the cartesian state vectors
1310 cart.reset();
1311
1312 // Compute the distance to the central body
1313 Real c_L{std::cos(anom.L)}, s_L{std::sin(anom.L)};
1314 Real alpha_2{equi.h*equi.h - equi.k*equi.k};
1315 Real s_2{1.0 + equi.h*equi.h + equi.k*equi.k};
1316 Real w{1.0 + equi.f*c_L + equi.g*s_L};
1317 Real r_c{equi.p / w};
1318
1319 // Compute the position and velocity vectors in the inertial frame
1320 Real tmp{r_c/s_2};
1321 cart.r <<
1322 tmp * (c_L + alpha_2*c_L + 2.0*equi.h*equi.k*s_L),
1323 tmp * (s_L - alpha_2*s_L + 2.0*equi.h*equi.k*c_L),
1324 2.0*tmp * (equi.h*s_L - equi.k*c_L);
1325
1326 std::cout << "cart.r = " << cart.r << std::endl;
1327
1328 tmp = -1.0/s_2 * std::sqrt(mu/equi.p);
1329 cart.v <<
1330 tmp * ( s_L + alpha_2*s_L - 2.0*equi.h*equi.k*c_L + equi.g - 2.0*equi.f*equi.h*equi.k + alpha_2*equi.g),
1331 tmp * (-c_L + alpha_2*c_L + 2.0*equi.h*equi.k*s_L - equi.f + 2.0*equi.g*equi.h*equi.k - alpha_2*equi.f),
1332 2.0*tmp * (-equi.h*c_L - equi.k*s_L + equi.f*equi.h - equi.g*equi.k);
1333
1334 std::cout << "cart.v = " << cart.v << std::endl;
1335
1336
1337 ASTRO_ASSERT(cart.sanity_check(), CMD "conversion error.");
1338
1339 #undef CMD
1340 }
1341
1349 {
1350 #define CMD "Astro::OrbitalElements::keplerian_to_equinoctial(...): "
1351
1352 // Reset the equinoctial orbital elements
1353 equi.reset();
1354
1355 // Compute the semi-latus rectum
1356 Real p{kepl.p()};
1357
1358 // Compute the x-axis component of the eccentricity vector in the orbital frame f
1359 Real omega_plus_Omega{kepl.omega + static_cast<Real>(I)*kepl.Omega};
1360 Real f{kepl.e * std::cos(omega_plus_Omega)};
1361
1362 // Compute the y-axis component of the eccentricity vector in the orbital frame g
1363 Real g{kepl.e * std::sin(omega_plus_Omega)};
1364
1365 // Compute the x- and y-axis components of the node vector in the orbital frame h
1366 Real tmp;
1367 tmp = std::tan(kepl.i / 2.0);
1368 if (I == Factor::RETROGRADE) {tmp = 1.0/tmp;} // 1/tan(x) = cot(x)
1369 Real h{tmp * std::cos(kepl.Omega)};
1370 Real k{tmp * std::sin(kepl.Omega)};
1371
1372 // Assign the equinoctial orbital elements
1373 equi.p = p;
1374 equi.f = f;
1375 equi.g = g;
1376 equi.h = h;
1377 equi.k = k;
1378
1379 ASTRO_ASSERT(equi.sanity_check(), CMD "conversion error.");
1380
1381 #undef CMD
1382 }
1383
1392 void equinoctial_to_cartesian(Equinoctial const & equi, Anomaly const & anom, Factor I, Real mu,
1393 Cartesian & cart)
1394 {
1395 #define CMD "Astro::OrbitalElements::equinoctial_to_cartesian(...): "
1396
1397 // Reset the cartesian state vectors
1398 cart.reset();
1399
1400 // Retrieve the equinoctial orbital elements
1401 Real p{equi.p};
1402 Real f{equi.f};
1403 Real g{equi.g};
1404 Real h{equi.h};
1405 Real k{equi.k};
1406
1407 // Compute the distance to the central body
1408 Real c_L{std::cos(anom.L)}, s_L{std::sin(anom.L)};
1409 Real h2{h*h}, k2{k*k}, hk{h*k};
1410 Real bf{p / ((1.0+f*c_L+g*s_L) * (1.0+h2+k2))};
1411 Real x{bf*c_L}, y{bf*s_L};
1412 Real bf1{std::sqrt(mu/p) / (1.0+h2+k2)};
1413 Real c_Lf{bf1 * (c_L+f)};
1414 Real s_Lg{bf1 * (s_L+g)};
1415
1416 // Compute the position and velocity vectors in the inertial frame
1417 cart.r <<
1418 (1.0+h2-k2)*x + 2.0*static_cast<Real>(I)*hk*y,
1419 static_cast<Real>(I)*(1.0-h2+k2)*y + 2.0*hk*x,
1420 2.0*(h*y-static_cast<Real>(I)*k*x);
1421 cart.v <<
1422 static_cast<Real>(I)*2.0*hk*c_Lf - (1.0+h2-k2)*s_Lg,
1423 static_cast<Real>(I)*(1.0-h2+k2)*c_Lf - 2.0*hk*s_Lg,
1424 2.0*(h*c_Lf + static_cast<Real>(I)*k*s_Lg);
1425
1426 ASTRO_ASSERT(cart.sanity_check(), CMD "conversion error.");
1427
1428 #undef CMD
1429 }
1430
1438 {
1439 #define CMD "Astro::OrbitalElements::equinoctial_to_keplerian(...): "
1440
1441 // Reset the keplerian orbital elements
1442 kepl.reset();
1443
1444 // Assign the keplerian orbital elements
1445 kepl.a = equi.a();
1446 kepl.e = equi.e();
1447 kepl.i = equi.i();
1448 kepl.Omega = equi.Omega();
1449 kepl.omega = equi.omega();
1450
1451 ASTRO_ASSERT(kepl.sanity_check(), CMD "conversion error.");
1452
1453 #undef CMD
1454 }
1455
1456 } // namespace OrbitalElements
1457
1458} // namespace Astro
1459
1460#endif // ASTRO_ORBITAL_ELEMENTS_HXX
#define ASTRO_ASSERT(COND, MSG)
Definition Astro.hh:42
#define ASTRO_WARNING(MSG)
Definition Astro.hh:51
#define ASTRO_ERROR(MSG)
Definition Astro.hh:31
#define ASTRO_ASSERT_WARNING(COND, MSG)
Definition Astro.hh:59
#define CMD
The namespace for the orbital elements definition and conversion.
Definition OrbitalElements.hxx:34
Real H_to_M(Real H, Keplerian const &kepl)
Definition OrbitalElements.hxx:886
void equinoctial_to_cartesian(Equinoctial const &equi, Anomaly const &anom, Real mu, Cartesian &cart)
Definition OrbitalElements.hxx:1305
Real lambda_to_L(Real lambda, Real nu, Real M)
Definition OrbitalElements.hxx:932
Real lambda_to_M(Real lambda, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:919
Real M_to_H(Real M, Keplerian const &kepl)
Definition OrbitalElements.hxx:800
Real M_to_E(Real M, Keplerian const &kepl)
Definition OrbitalElements.hxx:764
Real nu_to_L(Real nu, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:751
Real E_to_nu(Real E, Keplerian const &kepl)
Definition OrbitalElements.hxx:849
void keplerian_to_equinoctial(Keplerian const &kepl, Factor I, Equinoctial &equi)
Definition OrbitalElements.hxx:1348
Real nu_to_M(Real nu, Keplerian const &kepl)
Definition OrbitalElements.hxx:717
Real L_to_nu(Real L, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:896
Real H_to_nu(Real H, Keplerian const &kepl)
Definition OrbitalElements.hxx:874
void equinoctial_to_keplerian(Equinoctial const &equi, Keplerian &kepl)
Definition OrbitalElements.hxx:1437
void cartesian_to_keplerian(Cartesian const &cart, Real mu, Keplerian &kepl)
Definition OrbitalElements.hxx:1190
Real E_to_M(Real E, Keplerian const &kepl)
Definition OrbitalElements.hxx:862
Real nu_to_E(Real nu, Keplerian const &kepl)
Definition OrbitalElements.hxx:737
Real L_to_lambda(Real L, Real nu, Real M)
Definition OrbitalElements.hxx:909
Real M_to_lambda(Real M, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:832
void keplerian_to_cartesian(Keplerian const &kepl, Anomaly const &anom, Real mu, Cartesian &cart)
Definition OrbitalElements.hxx:1253
The namespace for the Astro library.
Definition Astro.hh:72
static Real const PI
Definition Utilities.hxx:57
Eigen::Quaternion< Real > Quaternion
Definition Astro.hh:111
static Real const EPSILON_HIGH
Definition Astro.hh:129
Real angle_in_range(Real x)
Definition Utilities.hxx:85
int Integer
Definition Astro.hh:84
static Vector3 const NAN_VEC3
Definition Astro.hh:151
Eigen::Matrix< Real, 3, 3 > Rotation
Definition Astro.hh:110
static Real const EPSILON_LOW
Definition Astro.hh:131
static Real const QUIET_NAN
Definition Astro.hh:133
enum class Type :Integer { UNDEFINED=0, HYPERBOLIC=1, ELLIPTIC=2, PARABOLIC=3 } Type
Definition OrbitalElements.hxx:24
static Vector4 const NAN_VEC4
Definition Astro.hh:159
double Real
Definition Astro.hh:83
Eigen::Vector< Real, 2 > Vector2
Definition Astro.hh:90
enum class Factor :Integer { POSIGRADE=1, UNDEFINED=0, RETROGRADE=-1 } Factor
Definition OrbitalElements.hxx:19
Eigen::Vector< Real, 3 > Vector3
Definition Astro.hh:92
Real rad_to_deg(Real x)
Definition Utilities.hxx:77
static Real const EPSILON_MEDIUM
Definition Astro.hh:130
Structure container for the orbital anomalies.
Definition OrbitalElements.hxx:955
void info(std::ostream &os)
Definition OrbitalElements.hxx:1130
void set_M(Real t_M, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:1012
void set_H(Real t_H, Keplerian const &kepl, Factor I)
Set the hyperbolic anomaly .
Definition OrbitalElements.hxx:1097
std::string info() const
Definition OrbitalElements.hxx:1114
Real H
Definition OrbitalElements.hxx:959
Real nu
Definition OrbitalElements.hxx:956
Anomaly()
Definition OrbitalElements.hxx:966
void set_lambda(Real t_lambda, Keplerian const &kepl, Factor I)
Set the mean longitude .
Definition OrbitalElements.hxx:1076
bool sanity_check() const
Definition OrbitalElements.hxx:1149
Real lambda
Definition OrbitalElements.hxx:961
void set_nu(Real nu, Keplerian const &kepl, Factor I)
Definition OrbitalElements.hxx:994
void reset()
Definition OrbitalElements.hxx:1135
Anomaly & operator=(Anomaly &&)=default
Anomaly & operator=(const Anomaly &)=default
Anomaly(Anomaly const &)=default
void set_E(Real t_E, Keplerian const &kepl, Factor I)
Set the eccentric anomaly .
Definition OrbitalElements.hxx:1035
void set_L(Real t_L, Keplerian const &kepl, Factor I)
Set the true longitude .
Definition OrbitalElements.hxx:1055
Real E
Definition OrbitalElements.hxx:958
Real L
Definition OrbitalElements.hxx:960
Real M
Definition OrbitalElements.hxx:957
Anomaly(Anomaly &&)=default
Structure container for the cartesian orbital elements.
Definition OrbitalElements.hxx:56
void info(std::ostream &os)
Definition OrbitalElements.hxx:120
Cartesian(Cartesian const &)=default
Vector3 v
Definition OrbitalElements.hxx:58
void reset()
Definition OrbitalElements.hxx:125
Cartesian(Cartesian &&)=default
Cartesian()
Definition OrbitalElements.hxx:63
Cartesian & operator=(Cartesian &&)=default
Cartesian(Vector3 const &t_r, Vector3 const &t_v)
Definition OrbitalElements.hxx:70
bool sanity_check() const
Definition OrbitalElements.hxx:133
Cartesian(Real r_x, Real r_y, Real r_z, Real v_x, Real v_y, Real v_z)
Definition OrbitalElements.hxx:81
Vector3 h() const
Definition OrbitalElements.hxx:153
Vector3 r
Definition OrbitalElements.hxx:57
std::string info() const
Definition OrbitalElements.hxx:108
Cartesian & operator=(const Cartesian &)=default
Struct container for the (modified) equinoctial orbital elements.
Definition OrbitalElements.hxx:382
Real Omega() const
Definition OrbitalElements.hxx:575
Real h
Definition OrbitalElements.hxx:386
Real g
Definition OrbitalElements.hxx:385
bool is_singular(Real tol_i=EPSILON_LOW) const
Definition OrbitalElements.hxx:501
Real a() const
Definition OrbitalElements.hxx:541
Equinoctial & operator=(Equinoctial &&)=default
Real omega() const
Definition OrbitalElements.hxx:563
Equinoctial(Real t_p, Real t_f, Real t_g, Real t_h, Real t_k)
Definition OrbitalElements.hxx:403
Real p
Definition OrbitalElements.hxx:383
Real u(Real L) const
Definition OrbitalElements.hxx:531
Real e() const
Definition OrbitalElements.hxx:547
Real f
Definition OrbitalElements.hxx:384
std::string info() const
Definition OrbitalElements.hxx:430
bool sanity_check() const
Definition OrbitalElements.hxx:462
void reset()
Definition OrbitalElements.hxx:450
Real i() const
Definition OrbitalElements.hxx:553
void info(std::ostream &os)
Definition OrbitalElements.hxx:445
Equinoctial(Equinoctial const &)=default
Equinoctial(Equinoctial &&)=default
Equinoctial & operator=(const Equinoctial &)=default
Real k
Definition OrbitalElements.hxx:387
Equinoctial()
Definition OrbitalElements.hxx:393
bool is_nonsingular(Real tol_i=EPSILON_LOW) const
Definition OrbitalElements.hxx:520
Structure container for the (modified) Keplerian orbital elements.
Definition OrbitalElements.hxx:193
Keplerian(Keplerian const &)=default
Real i
Definition OrbitalElements.hxx:196
std::string info() const
Definition OrbitalElements.hxx:241
Keplerian(Keplerian &&)=default
Real p() const
Definition OrbitalElements.hxx:353
bool is_nonsingular(Real tol_i=EPSILON_LOW, Real tol_e=EPSILON_LOW) const
Definition OrbitalElements.hxx:338
void reset()
Definition OrbitalElements.hxx:261
Real omega
Definition OrbitalElements.hxx:198
Keplerian & operator=(Keplerian &&)=default
Keplerian & operator=(const Keplerian &)=default
Real e
Definition OrbitalElements.hxx:195
Real Omega
Definition OrbitalElements.hxx:197
void info(std::ostream &os)
Definition OrbitalElements.hxx:256
Keplerian(Real t_a, Real t_e, Real t_i, Real t_Omega, Real t_omega)
Definition OrbitalElements.hxx:213
Real a
Definition OrbitalElements.hxx:194
bool sanity_check() const
Definition OrbitalElements.hxx:276
Real u() const
Definition OrbitalElements.hxx:347
Keplerian()
Definition OrbitalElements.hxx:203
bool is_singular(Real tol_i=EPSILON_LOW, Real tol_e=EPSILON_LOW) const
Definition OrbitalElements.hxx:313
Quaternionic()
Definition OrbitalElements.hxx:606
Quaternionic(Real t_q_1, Real t_q_2, Real t_q_3, Real t_q_4)
Definition OrbitalElements.hxx:621
Quaternionic(Quaternion const &t_q)
Definition OrbitalElements.hxx:612
void reset()
Definition OrbitalElements.hxx:683
Quaternionic(Quaternionic &&)=default
Quaternion q
Definition OrbitalElements.hxx:601
Quaternionic & operator=(const Quaternionic &)=default
std::string info() const
Definition OrbitalElements.hxx:664
bool sanity_check() const
Definition OrbitalElements.hxx:689
Quaternionic & operator=(Quaternionic &&)=default
void info(std::ostream &os)
Definition OrbitalElements.hxx:678
Rotation rotation() const
Definition OrbitalElements.hxx:646
Quaternionic(Quaternionic const &)=default