@ -0,0 +1,139 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MATH_TRANSFORMATION_SE3_HPP | |||||
#define ANTKEEPER_MATH_TRANSFORMATION_SE3_HPP | |||||
#include "math/vector-type.hpp" | |||||
#include "math/vector-operators.hpp" | |||||
#include "math/quaternion-type.hpp" | |||||
#include "math/quaternion-operators.hpp" | |||||
#include "math/quaternion-functions.hpp" | |||||
namespace math { | |||||
namespace transformation { | |||||
/** | |||||
* 3-dimensional Euclidean proper rigid transformation in SE(3). | |||||
* | |||||
* @tparam T Scalar type. | |||||
*/ | |||||
template <class T> | |||||
struct se3 | |||||
{ | |||||
public: | |||||
/// Scalar type. | |||||
typedef T scalar_type; | |||||
/// Vector type. | |||||
typedef math::vector3<T> vector_type; | |||||
/// Quaternion type. | |||||
typedef math::quaternion<T> quaternion_type; | |||||
/// Transformation matrix type. | |||||
typedef math::matrix<T, 4, 4> matrix_type; | |||||
/// Vector representing the translation component of this SE(3) transformation. | |||||
vector_type t; | |||||
/// Quaternion representing the rotation component of this SE(3) transformation. | |||||
quaternion_type r; | |||||
/// Returns the inverse of this SE(3) transformation. | |||||
se3 inverse() const; | |||||
/// Returns a matrix representation of the SE(3) transformation. | |||||
matrix_type matrix() const; | |||||
/** | |||||
* Transforms a vector by this SE(3) transformation. | |||||
* | |||||
* @param x Untransformed vector. | |||||
* @return Transformed vector. | |||||
*/ | |||||
vector_type transform(const vector_type& x) const; | |||||
/** | |||||
* Transforms an SE(3) transformation by this SE(3) transformation. | |||||
* | |||||
* @param x Other SE(3) transformation. | |||||
* @return Frame in this se3's space. | |||||
*/ | |||||
se3 transform(const se3& x) const; | |||||
/// @copydoc se3::transform(const vector_type&) const | |||||
vector_type operator*(const vector_type& x) const; | |||||
/// @copydoc se3::transform(const se3&) const | |||||
se3 operator*(const se3& x) const; | |||||
}; | |||||
template <class T> | |||||
se3<T> se3<T>::inverse() const | |||||
{ | |||||
const quaternion_type inverse_r = math::conjugate(r); | |||||
const vector_type inverse_t = -(inverse_r * t); | |||||
return se3{inverse_t, inverse_r}; | |||||
} | |||||
template <class T> | |||||
typename se3<T>::matrix_type se3<T>::matrix() const | |||||
{ | |||||
matrix_type m = math::resize<4, 4>(math::matrix_cast<T>(r)); | |||||
m[3].x = t.x; | |||||
m[3].y = t.y; | |||||
m[3].z = t.z; | |||||
return m; | |||||
} | |||||
template <class T> | |||||
typename se3<T>::vector_type se3<T>::transform(const vector_type& x) const | |||||
{ | |||||
return r * x + t; | |||||
} | |||||
template <class T> | |||||
se3<T> se3<T>::transform(const se3& x) const | |||||
{ | |||||
return se3 | |||||
{ | |||||
x.transform(t), | |||||
math::normalize(x.r * r) | |||||
}; | |||||
} | |||||
template <class T> | |||||
typename se3<T>::vector_type se3<T>::operator*(const vector_type& x) const | |||||
{ | |||||
return transform(x); | |||||
} | |||||
template <class T> | |||||
se3<T> se3<T>::operator*(const se3& x) const | |||||
{ | |||||
return transform(x); | |||||
} | |||||
} // namespace transformation | |||||
} // namespace math | |||||
#endif // ANTKEEPER_MATH_TRANSFORMATION_SE3_HPP |
@ -1,134 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PHYSICS_FRAME_HPP | |||||
#define ANTKEEPER_PHYSICS_FRAME_HPP | |||||
#include "math/math.hpp" | |||||
#include <cmath> | |||||
namespace physics { | |||||
/** | |||||
* 3-dimensional frame of reference. | |||||
* | |||||
* @tparam T Scalar type. | |||||
*/ | |||||
template <class T> | |||||
struct frame | |||||
{ | |||||
public: | |||||
/// Scalar type. | |||||
typedef T scalar_type; | |||||
/// Vector type. | |||||
typedef math::vector3<T> vector_type; | |||||
/// Quaternion type. | |||||
typedef math::quaternion<T> quaternion_type; | |||||
/// Transformation matrix type. | |||||
typedef math::matrix<T, 4, 4> matrix_type; | |||||
/// Vector representing a translation from the origin of this frame to the origin of the parent frame. | |||||
vector_type translation; | |||||
/// Quaternion representing a rotation from the orientation of this frame to the orientation of the parent frame. | |||||
quaternion_type rotation; | |||||
/// Returns the inverse of this frame. | |||||
frame inverse() const; | |||||
/// Returns a transformation matrix representation of this frame. | |||||
matrix_type matrix() const; | |||||
/** | |||||
* Transforms a vector from the parent frame space to this frame's space. | |||||
* | |||||
* @param v Vector in parent frame space. | |||||
* @return Vector in this frame's space. | |||||
*/ | |||||
vector_type transform(const vector_type& v) const; | |||||
/** | |||||
* Transforms a frame from the parent frame space to this frame's space. | |||||
* | |||||
* @param f Frame in parent frame space. | |||||
* @return Frame in this frame's space. | |||||
*/ | |||||
frame transform(const frame& f) const; | |||||
/// @copydoc frame::transform(const vector_type&) const | |||||
vector_type operator*(const vector_type& v) const; | |||||
/// @copydoc frame::transform(const frame&) const | |||||
frame operator*(const frame& f) const; | |||||
}; | |||||
template <class T> | |||||
frame<T> frame<T>::inverse() const | |||||
{ | |||||
const quaternion_type inverse_rotation = math::conjugate(rotation); | |||||
const vector_type inverse_translation = -(inverse_rotation * translation); | |||||
return frame{inverse_translation, inverse_rotation}; | |||||
} | |||||
template <class T> | |||||
typename frame<T>::matrix_type frame<T>::matrix() const | |||||
{ | |||||
matrix_type m = math::resize<4, 4>(math::matrix_cast<T>(rotation)); | |||||
m[3].x = translation.x; | |||||
m[3].y = translation.y; | |||||
m[3].z = translation.z; | |||||
return m; | |||||
} | |||||
template <class T> | |||||
typename frame<T>::vector_type frame<T>::transform(const vector_type& v) const | |||||
{ | |||||
return translation + rotation * v; | |||||
} | |||||
template <class T> | |||||
frame<T> frame<T>::transform(const frame& f) const | |||||
{ | |||||
return frame | |||||
{ | |||||
f.transform(translation), | |||||
math::normalize(f.rotation * rotation) | |||||
}; | |||||
} | |||||
template <class T> | |||||
typename frame<T>::vector_type frame<T>::operator*(const vector_type& v) const | |||||
{ | |||||
return transform(v); | |||||
} | |||||
template <class T> | |||||
frame<T> frame<T>::operator*(const frame& f) const | |||||
{ | |||||
return transform(f); | |||||
} | |||||
} // namespace physics | |||||
#endif // ANTKEEPER_PHYSICS_FRAME_HPP |
@ -0,0 +1,199 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP | |||||
#define ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP | |||||
#include "math/constants.hpp" | |||||
#include <cmath> | |||||
namespace physics { | |||||
namespace orbit { | |||||
/** | |||||
* Orbital anomaly functions. | |||||
*/ | |||||
namespace anomaly { | |||||
/** | |||||
* Derives the eccentric anomaly given eccentricity and true anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ta True anomaly (nu). | |||||
* @return Eccentric anomaly (E). | |||||
*/ | |||||
template <class T> | |||||
T true_to_eccentric(T ec, T ta); | |||||
/** | |||||
* Derives the mean anomaly given eccentricity and true anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ta True anomaly (nu). | |||||
* @return Mean anomaly (M). | |||||
*/ | |||||
template <class T> | |||||
T true_to_mean(T ec, T ta); | |||||
/** | |||||
* Derives the true anomaly given eccentricity and eccentric anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ea Eccentric anomaly (E). | |||||
* @return True anomaly (nu). | |||||
*/ | |||||
template <class T> | |||||
T eccentric_to_true(T ec, T ea); | |||||
/** | |||||
* Derives the mean anomaly given eccentricity and eccentric anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ea Eccentric anomaly (E). | |||||
* @return Mean anomaly (M). | |||||
*/ | |||||
template <class T> | |||||
T eccentric_to_mean(T ec, T ea); | |||||
/** | |||||
* Iteratively derives the eccentric anomaly given eccentricity and mean anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ma Mean anomaly (M). | |||||
* @param iterations Maximum number of iterations. | |||||
* @param tolerance Solution error tolerance. | |||||
* @return Eccentric anomaly (E). | |||||
* | |||||
* @see Murison, Marc. (2006). A Practical Method for Solving the Kepler Equation. 10.13140/2.1.5019.6808. | |||||
*/ | |||||
template <class T> | |||||
T mean_to_eccentric(T ec, T ma, std::size_t iterations, T tolerance); | |||||
/** | |||||
* Iteratively derives the true anomaly given eccentricity and mean anomaly. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ma Mean anomaly (M). | |||||
* @param iterations Maximum number of iterations. | |||||
* @param tolerance Solution error tolerance. | |||||
* @return True anomaly (nu). | |||||
*/ | |||||
template <class T> | |||||
T mean_to_true(T ec, T ma, std::size_t iterations, T tolerance); | |||||
template <class T> | |||||
T true_to_eccentric(T ec, T ta) | |||||
{ | |||||
// Parabolic orbit | |||||
if (ec == T(1)) | |||||
return std::tan(ta * T(0.5)); | |||||
// Hyperbolic orbit | |||||
if (ec > T(1)) | |||||
return std::acosh((ec + std::cos(ta)) / (T(1) + ec * std::cos(ta))) * ((ta < T(0)) ? T(-1) : T(1)); | |||||
// Elliptic orbit | |||||
return std::atan2(std::sqrt(T(1) - ec * ec) * std::sin(ta), std::cos(ta) + ec); | |||||
} | |||||
template <class T> | |||||
T true_to_mean(T ec, T ta) | |||||
{ | |||||
return eccentric_to_mean(ec, true_to_eccentric(ec, ta)); | |||||
} | |||||
template <class T> | |||||
T eccentric_to_true(T ec, T ea) | |||||
{ | |||||
// Parabolic orbit | |||||
if (ec == T(1)) | |||||
return std::atan(ea) * T(2); | |||||
// Hyperbolic orbit | |||||
if (ec > T(1)) | |||||
return std::atan(std::sqrt((ec + T(1)) / (ec - T(1))) * std::tanh(ea * T(0.5))) * T(2); | |||||
// Elliptic orbit | |||||
return std::atan2(sqrt(T(1) - ec * ec) * std::sin(ea), std::cos(ea) - ec); | |||||
} | |||||
template <class T> | |||||
T eccentric_to_mean(T ec, T ea) | |||||
{ | |||||
// Parabolic orbit | |||||
if (ec == T(1)) | |||||
return (ea * ea * ea) / T(6) + ea * T(0.5); | |||||
// Hyperbolic orbit | |||||
if (ec > T(1)) | |||||
return ec * std::sinh(ea) - ea; | |||||
// Elliptic orbit | |||||
return ea - ec * std::sin(ea); | |||||
} | |||||
template <class T> | |||||
T mean_to_eccentric(T ec, T ma, std::size_t iterations, T tolerance) | |||||
{ | |||||
// Wrap mean anomaly to `[-pi, pi]` | |||||
ma = std::remainder(ma, math::two_pi<T>); | |||||
// Third-order approximation of eccentric anomaly starting value, E0 | |||||
const T t33 = std::cos(ma); | |||||
const T t34 = ec * ec; | |||||
const T t35 = t34 * ec; | |||||
T ea0 = ma + (T(-0.5) * t35 + ec + (t34 + T(1.5) * t33 * t35) * t33) * std::sin(ma); | |||||
// Iteratively converge E0 and E1 | |||||
for (std::size_t i = 0; i < iterations; ++i) | |||||
{ | |||||
// Third-order approximation of eccentric anomaly, E1 | |||||
const T t1 = std::cos(ea0); | |||||
const T t2 = T(-1) + ec * t1; | |||||
const T t3 = std::sin(ea0); | |||||
const T t4 = ec * t3; | |||||
const T t5 = -ea0 + t4 + ma; | |||||
const T t6 = t5 / (T(0.5) * t5 * t4 / t2 + t2); | |||||
const T ea1 = ea0 - (t5 / ((T(0.5) * t3 - (T(1) / T(6)) * t1 * t6) * ec * t6 + t2)); | |||||
// Determine solution error | |||||
const T error = std::abs(ea1 - ea0); | |||||
// Set E0 to E1 | |||||
ea0 = ea1; | |||||
// Break if solution is within error tolerance | |||||
if (error < tolerance) | |||||
break; | |||||
} | |||||
return ea0; | |||||
} | |||||
template <class T> | |||||
T mean_to_true(T ec, T ma, std::size_t iterations, T tolerance) | |||||
{ | |||||
eccentric_to_true(ec, mean_to_eccentric(ec, ma, iterations, tolerance)); | |||||
} | |||||
} // namespace anomaly | |||||
} // namespace orbit | |||||
} // namespace physics | |||||
#endif // ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP |
@ -0,0 +1,399 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP | |||||
#define ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP | |||||
#include "math/se3.hpp" | |||||
#include <cmath> | |||||
namespace physics { | |||||
namespace orbit { | |||||
/// Orbital reference frames. | |||||
namespace frame { | |||||
/// Perifocal (PQW) frame. | |||||
namespace pqw { | |||||
/** | |||||
* Converts PQW coordinates from Cartesian to spherical. | |||||
* | |||||
* @param v PQW Cartesian coordinates. | |||||
* @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(const math::vector3<T>& v) | |||||
{ | |||||
const T xx_yy = v.x * v.x + v.y * v.y; | |||||
return math::vector3<T> | |||||
{ | |||||
std::sqrt(xx_yy + v.z * v.z), | |||||
std::atan2(v.z, std::sqrt(xx_yy)), | |||||
std::atan2(v.y, v.x) | |||||
}; | |||||
} | |||||
/** | |||||
* Constructs spherical PQW coordinates from Keplerian orbital elements. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param a Semimajor axis (a). | |||||
* @param ea Eccentric anomaly (E), in radians. | |||||
* @param b Semiminor axis (b). | |||||
* @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(T ec, T a, T ea, T b) | |||||
{ | |||||
const T x = a * (std::cos(ea) - ec); | |||||
const T y = b * std::sin(ea); | |||||
const T d = std::sqrt(x * x + y * y); | |||||
const T ta = std::atan2(y, x); | |||||
return math::vector3<T>{d, T(0), ta}; | |||||
} | |||||
/** | |||||
* Constructs spherical PQW coordinates from Keplerian orbital elements. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param a Semimajor axis (a). | |||||
* @param ea Eccentric anomaly (E), in radians. | |||||
* @return PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(T ec, T a, T ea) | |||||
{ | |||||
const T b = a * std::sqrt(T(1) - ec * ec); | |||||
return spherical<T>(ec, a, ea, b); | |||||
} | |||||
/** | |||||
* Converts PQW coordinates from spherical to Cartesian. | |||||
* | |||||
* @param PQW spherical coordinates, in the ISO order of radial distance, inclination (radians), and true anomaly (radians). | |||||
* @return PQW Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(const math::vector3<T>& v) | |||||
{ | |||||
const T x = v[0] * std::cos(v[1]); | |||||
return math::vector3<T> | |||||
{ | |||||
x * std::cos(v[2]), | |||||
x * std::sin(v[2]), | |||||
v[0] * std::sin(v[1]), | |||||
}; | |||||
} | |||||
/** | |||||
* Constructs Cartesian PQW coordinates from Keplerian orbital elements. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param a Semimajor axis (a). | |||||
* @param ea Eccentric anomaly (E), in radians. | |||||
* @param b Semiminor axis (b). | |||||
* @return PQW Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(T ec, T a, T ea, T b) | |||||
{ | |||||
return cartesian<T>(spherical<T>(ec, a, ea, b)); | |||||
} | |||||
/** | |||||
* Constructs Cartesian PQW coordinates from Keplerian orbital elements. | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param a Semimajor axis (a). | |||||
* @param ea Eccentric anomaly (E), in radians. | |||||
* @return PQW Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(T ec, T a, T ea) | |||||
{ | |||||
return cartesian<T>(spherical<T>(ec, a, ea)); | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from a PQW frame to a BCI frame. | |||||
* | |||||
* @param om Right ascension of the ascending node (OMEGA), in radians. | |||||
* @param in Orbital inclination (i), in radians. | |||||
* @param w Argument of periapsis (omega), in radians. | |||||
* @return PQW to BCI transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_bci(T om, T in, T w) | |||||
{ | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(om) * | |||||
math::quaternion<T>::rotate_x(in) * | |||||
math::quaternion<T>::rotate_z(w) | |||||
); | |||||
return math::transformation::se3<T>{{T(0), T(0), T(0)}, r}; | |||||
} | |||||
} // namespace pqw | |||||
/// Body-centered inertial (BCI) frame. | |||||
namespace bci { | |||||
/** | |||||
* Converts BCI coordinates from spherical to Cartesian. | |||||
* | |||||
* @param v BCI spherical coordinates, in the ISO order of radial distance, declination (radians), and right ascension (radians). | |||||
* @return BCI Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(const math::vector3<T>& v) | |||||
{ | |||||
const T x = v[0] * std::cos(v[1]); | |||||
return math::vector3<T> | |||||
{ | |||||
x * std::cos(v[2]), | |||||
x * std::sin(v[2]), | |||||
v[0] * std::sin(v[1]), | |||||
}; | |||||
} | |||||
/** | |||||
* Converts BCI coordinates from Cartesian to spherical. | |||||
* | |||||
* @param v BCI Cartesian coordinates. | |||||
* @return BCI spherical coordinates, in the ISO order of radial distance, declination (radians), and right ascension (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(const math::vector3<T>& v) | |||||
{ | |||||
const T xx_yy = v.x * v.x + v.y * v.y; | |||||
return math::vector3<T> | |||||
{ | |||||
std::sqrt(xx_yy + v.z * v.z), | |||||
std::atan2(v.z, std::sqrt(xx_yy)), | |||||
std::atan2(v.y, v.x) | |||||
}; | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from a BCI frame to a BCBF frame. | |||||
* | |||||
* @param ra Right ascension of the north pole, in radians. | |||||
* @param dec Declination of the north pole, in radians. | |||||
* @param w Location of the prime meridian, as a rotation about the north pole, in radians. | |||||
* @return BCI to BCBF transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_bcbf(T ra, T dec, T w) | |||||
{ | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(-w) * | |||||
math::quaternion<T>::rotate_x(-math::half_pi<T> + dec) * | |||||
math::quaternion<T>::rotate_z(-math::half_pi<T> - ra) | |||||
); | |||||
return math::transformation::se3<T>{{T(0), T(0), T(0)}, r}; | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from a BCI frame to a PQW frame. | |||||
* | |||||
* @param om Right ascension of the ascending node (OMEGA), in radians. | |||||
* @param in Orbital inclination (i), in radians. | |||||
* @param w Argument of periapsis (omega), in radians. | |||||
* @return BCI to PQW transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_pqw(T om, T in, T w) | |||||
{ | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(-w) * | |||||
math::quaternion<T>::rotate_x(-in) * | |||||
math::quaternion<T>::rotate_z(-om) | |||||
); | |||||
return math::transformation::se3<T>{{T(0), T(0), T(0)}, r}; | |||||
} | |||||
} // namespace bci | |||||
/// Body-centered, body-fixed (BCBF) frame. | |||||
namespace bcbf { | |||||
/** | |||||
* Converts BCBF coordinates from spherical to Cartesian. | |||||
* | |||||
* @param v BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians). | |||||
* @return BCBF Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(const math::vector3<T>& v) | |||||
{ | |||||
const T x = v[0] * std::cos(v[1]); | |||||
return math::vector3<T> | |||||
{ | |||||
x * std::cos(v[2]), | |||||
x * std::sin(v[2]), | |||||
v[0] * std::sin(v[1]), | |||||
}; | |||||
} | |||||
/** | |||||
* Converts BCBF coordinates from Cartesian to spherical. | |||||
* | |||||
* @param v BCBF Cartesian coordinates. | |||||
* @return BCBF spherical coordinates, in the ISO order of radial distance, latitude (radians), and longitude (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(const math::vector3<T>& v) | |||||
{ | |||||
const T xx_yy = v.x * v.x + v.y * v.y; | |||||
return math::vector3<T> | |||||
{ | |||||
std::sqrt(xx_yy + v.z * v.z), | |||||
std::atan2(v.z, std::sqrt(xx_yy)), | |||||
std::atan2(v.y, v.x) | |||||
}; | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from a BCBF frame to a BCI frame. | |||||
* | |||||
* @param ra Right ascension of the north pole, in radians. | |||||
* @param dec Declination of the north pole, in radians. | |||||
* @param w Location of the prime meridian, as a rotation about the north pole, in radians. | |||||
* @return BCBF to BCI transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_bci(T ra, T dec, T w) | |||||
{ | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(math::half_pi<T> + ra) * | |||||
math::quaternion<T>::rotate_x(math::half_pi<T> - dec) * | |||||
math::quaternion<T>::rotate_z(w) | |||||
); | |||||
return math::transformation::se3<T>{{T(0), T(0), T(0)}, r}; | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from a BCBF frame to an ENU frame. | |||||
* | |||||
* @param distance Radial distance of the observer from the center of the body. | |||||
* @param latitude Latitude of the observer, in radians. | |||||
* @param longitude Longitude of the observer, in radians. | |||||
* @return BCBF to ENU transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_enu(T distance, T latitude, T longitude) | |||||
{ | |||||
const math::vector3<T> t = {T(0), T(0), -distance}; | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_x(-math::half_pi<T> + latitude) * | |||||
math::quaternion<T>::rotate_z(-longitude - math::half_pi<T>) | |||||
); | |||||
return math::transformation::se3<T>{t, r}; | |||||
} | |||||
} // namespace bcbf | |||||
/// East, North, Up (ENU) horizontal frame. | |||||
namespace enu { | |||||
/** | |||||
* Converts ENU coordinates from spherical to Cartesian. | |||||
* | |||||
* @param v ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians). | |||||
* @return ENU Cartesian coordinates. | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> cartesian(const math::vector3<T>& v) | |||||
{ | |||||
const T x = v[0] * std::cos(v[1]); | |||||
const T y = math::half_pi<T> - v[2]; | |||||
return math::vector3<T> | |||||
{ | |||||
x * std::cos(y), | |||||
x * std::sin(y), | |||||
v[0] * std::sin(v[1]), | |||||
}; | |||||
} | |||||
/** | |||||
* Converts ENU coordinates from Cartesian to spherical. | |||||
* | |||||
* @param v ENU Cartesian coordinates. | |||||
* @return ENU spherical coordinates, in the ISO order of radial distance, elevation (radians), and azimuth (radians). | |||||
*/ | |||||
template <class T> | |||||
math::vector3<T> spherical(const math::vector3<T>& v) | |||||
{ | |||||
const T xx_yy = v.x * v.x + v.y * v.y; | |||||
return math::vector3<T> | |||||
{ | |||||
std::sqrt(xx_yy + v.z * v.z), | |||||
std::atan2(v.z, std::sqrt(xx_yy)), | |||||
math::half_pi<T> - std::atan2(v.y, v.x) | |||||
}; | |||||
} | |||||
/** | |||||
* Constructs an SE(3) transformation from an ENU frame to a BCBF frame. | |||||
* | |||||
* @param distance Radial distance of the observer from the center of the body. | |||||
* @param latitude Latitude of the observer, in radians. | |||||
* @param longitude Longitude of the observer, in radians. | |||||
* @return ENU to BCBF transformation. | |||||
*/ | |||||
template <typename T> | |||||
math::transformation::se3<T> to_bcbf(T distance, T latitude, T longitude) | |||||
{ | |||||
const math::vector3<T> t = {T(0), T(0), distance}; | |||||
const math::quaternion<T> r = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(longitude + math::half_pi<T>) * | |||||
math::quaternion<T>::rotate_x(math::half_pi<T> - latitude) | |||||
); | |||||
return math::transformation::se3<T>{r * t, r}; | |||||
} | |||||
} // namespace enu | |||||
} // namespace frame | |||||
} // namespace orbit | |||||
} // namespace physics | |||||
#endif // ANTKEEPER_PHYSICS_ORBIT_FRAME_HPP |
@ -1,131 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PHYSICS_ORBIT_FRAMES_HPP | |||||
#define ANTKEEPER_PHYSICS_ORBIT_FRAMES_HPP | |||||
#include "physics/frame.hpp" | |||||
namespace physics { | |||||
namespace orbit { | |||||
/// Inertial right-handed coordinate system | |||||
namespace inertial { | |||||
/** | |||||
* Constucts a reference frame which transforms coordinates from inertial space into perifocal space. | |||||
* | |||||
* @param focus Cartesian coordinates of the focus of the orbit, in the parent space. | |||||
* @param raan Right ascension of the ascending node (OMEGA), in radians. | |||||
* @param i Orbital inclination (i), in radians. | |||||
* @param w Argument of periapsis (omega), in radians. | |||||
* @return Perifocal frame. | |||||
*/ | |||||
template <typename T> | |||||
physics::frame<T> to_perifocal(const math::vector3<T>& focus, T raan, T i, T w) | |||||
{ | |||||
const math::quaternion<T> rotation = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(raan) * | |||||
math::quaternion<T>::rotate_x(i) * | |||||
math::quaternion<T>::rotate_z(w) | |||||
); | |||||
return physics::frame<T>{focus, rotation}.inverse(); | |||||
} | |||||
/** | |||||
* Constructs a reference frame which transforms coordinates from inertial space to body-centered inertial space. | |||||
* | |||||
* @param r Cartesian position vector (r) of the center of the body, in inertial space. | |||||
* @param i Orbital inclination (i), in radians. | |||||
* @param axial_tilt Angle between the body's rotational axis and its orbital axis, in radians. | |||||
* @return Body-centered inertial frame. | |||||
*/ | |||||
template <typename T> | |||||
physics::frame<T> to_bci(const math::vector3<T>& r, T i, T axial_tilt) | |||||
{ | |||||
return physics::frame<T>{r, math::quaternion<T>::rotate_x(-axial_tilt - i)}.inverse(); | |||||
} | |||||
/** | |||||
* Constructs a reference frame which transforms coordinates from inertial space to body-centered, body-fixed space. | |||||
* | |||||
* @param r Cartesian position vector (r) of the center of the body, in inertial space. | |||||
* @param i Orbital inclination (i), in radians. | |||||
* @param axial_tilt Angle between the orbiting body's rotational axis and its orbital axis, in radians. | |||||
* @param axial_rotation Angle of rotation about the orbiting body's rotational axis, in radians. | |||||
*/ | |||||
template <typename T> | |||||
frame<T> to_bcbf(const math::vector3<T>& r, T i, T axial_tilt, T axial_rotation) | |||||
{ | |||||
const math::quaternion<T> rotation = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_x(-axial_tilt - i) * | |||||
math::quaternion<T>::rotate_z(axial_rotation) | |||||
); | |||||
return physics::frame<T>{r, rotation}.inverse(); | |||||
} | |||||
} // namespace inertial | |||||
/// Perifocal right-handed coordinate system in which the x-axis points toward the periapsis of the orbit, the y-axis has a true anomaly of 90 degrees past the periapsis, and the z-axis is the angular momentum vector, which is orthogonal to the orbital plane. | |||||
namespace perifocal { | |||||
} // namespace perifocal | |||||
/// Non-inertial body-centered, body-fixed right-handed coordinate system. The x-axis is orthogonal to the intersection of the prime meridian and the equator. The z-axis points toward the positive pole. The y-axis is right-hand orthogonal to the xz-plane. | |||||
namespace bcbf { | |||||
/** | |||||
* Constructs a reference frame which transforms coordinates from BCBF space to topocentric space. | |||||
* | |||||
* @param distance Radial distance of the observer from the center of the body. | |||||
* @param latitude Latitude of the observer, in radians. | |||||
* @param longitude Longitude of the obserer, in radians. | |||||
* @return Topocentric frame. | |||||
*/ | |||||
template <typename T> | |||||
physics::frame<T> to_topocentric(T distance, T latitude, T longitude) | |||||
{ | |||||
const math::vector3<T> translation = {T(0), T(0), distance}; | |||||
const math::quaternion<T> rotation = math::normalize | |||||
( | |||||
math::quaternion<T>::rotate_z(longitude) * | |||||
math::quaternion<T>::rotate_y(math::half_pi<T> - latitude) | |||||
); | |||||
return physics::frame<T>{rotation * translation, rotation}.inverse(); | |||||
} | |||||
} // namespace bcbf | |||||
/// Non-inertial topocentric right-handed coordinate system. Topocentric frames are constructed as south-east-zenith (SEZ) frames; the x-axis points south, the y-axis points east, and the z-axis points toward the zenith (orthogonal to reference spheroid). | |||||
namespace topocentric { | |||||
} // namespace topocentric | |||||
} // namespace orbit | |||||
} // namespace physics | |||||
#endif // ANTKEEPER_PHYSICS_ORBIT_FRAMES_HPP |
@ -1,79 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2021 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PHYSICS_ORBIT_KEPLER_HPP | |||||
#define ANTKEEPER_PHYSICS_ORBIT_KEPLER_HPP | |||||
#include <cmath> | |||||
namespace physics { | |||||
namespace orbit { | |||||
/** | |||||
* Iteratively solves Kepler's equation for eccentric anomaly (E). | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ma Mean anomaly (M). | |||||
* @param iterations Maximum number of iterations. | |||||
* @param tolerance Solution error tolerance. | |||||
* @return Eccentric anomaly (E). | |||||
*/ | |||||
template <class T> | |||||
T kepler_ea(T ec, T ma, std::size_t iterations, T tolerance = T(0)); | |||||
/** | |||||
* Solves Kepler's equation for mean anomaly (M). | |||||
* | |||||
* @param ec Eccentricity (e). | |||||
* @param ea Eccentric anomaly (E). | |||||
* @return Mean anomaly (M). | |||||
*/ | |||||
template <class T> | |||||
T kepler_ma(T ec, T ea); | |||||
template <class T> | |||||
T kepler_ea(T ec, T ma, std::size_t iterations, T tolerance) | |||||
{ | |||||
// Approximate eccentric anomaly, E | |||||
T ea0 = ma + ec * std::sin(ma) * (T(1.0) + ec * std::cos(ma)); | |||||
// Iteratively converge E0 and E1 | |||||
for (std::size_t i = 0; i < iterations; ++i) | |||||
{ | |||||
const T ea1 = ea0 - (ea0 - ec * std::sin(ea0) - ma) / (T(1.0) - ec * std::cos(ea0)); | |||||
const T error = std::abs(ea1 - ea0); | |||||
ea0 = ea1; | |||||
if (error < tolerance) | |||||
break; | |||||
} | |||||
return ea0; | |||||
} | |||||
template <class T> | |||||
T kepler_ma(T ec, T ea) | |||||
{ | |||||
return ea - ec * std::sin(ea); | |||||
} | |||||
} // namespace orbit | |||||
} // namespace physics | |||||
#endif // ANTKEEPER_PHYSICS_ORBIT_KEPLER_HPP |