@ -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 |