9#include "../astro_context.hpp"
10#include "../centers.hpp"
11#include "../constants.hpp"
12#include "../frames.hpp"
16#include <qtty/qtty.hpp>
27template <
typename C,
typename F,
typename U>
struct Position;
51 static_assert(frames::is_frame_v<F>,
"F must be a valid frame tag");
54 qtty::Degree azimuth_;
70 template <
typename F_ = F, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
71 qtty::Degree
ra()
const {
75 template <
typename F_ = F, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
76 qtty::Degree
dec()
const {
83 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
84 qtty::Degree
az()
const {
88 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
89 qtty::Degree
al()
const {
93 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
94 qtty::Degree
alt()
const {
98 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
106 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
107 qtty::Degree
lon()
const {
111 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
112 qtty::Degree
lat()
const {
116 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
121 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
132 return Direction(qtty::Degree(
c.azimuth_deg), qtty::Degree(
c.polar_deg));
147 const double az1 = azimuth_.value() *
DEG2RAD;
153 const double y = std::cos(
po2) * std::sin(
az2 -
az1);
156 return qtty::Degree(std::atan2(std::sqrt(x * x + y * y), z) *
RAD2DEG);
167 template <
typename Target>
170 if constexpr (std::is_same_v<F, Target>) {
177 "Direction::to_frame");
185 template <
typename Target>
188 if constexpr (std::is_same_v<F, Target>) {
196 "Direction::to_frame_with");
204 template <
typename Target>
217 const double az = azimuth_.value() *
DEG2RAD;
218 const double po = polar_.value() *
DEG2RAD;
219 const double cp = std::cos(
po);
226 template <
typename F_ = F>
233 "Direction::to_horizontal");
240 template <
typename F_ = F>
249 "Direction::to_horizontal_with");
264 template <
typename F_ = F>
272 "Direction::to_horizontal_precise");
287template <
typename C,
typename F,
typename U = qtty::Meter>
struct Position {
288 static_assert(frames::is_frame_v<F>,
"F must be a valid frame tag");
289 static_assert(centers::is_center_v<C>,
"C must be a valid center tag");
292 qtty::Degree azimuth_;
308 template <
typename F_ = F, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
309 qtty::Degree
ra()
const {
313 template <
typename F_ = F, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
314 qtty::Degree
dec()
const {
318 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
319 qtty::Degree
az()
const {
323 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
324 qtty::Degree
al()
const {
328 template <
typename F_ = F, std::enable_if_t<frames::has_az_alt_v<F_>,
int> = 0>
329 qtty::Degree
alt()
const {
333 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
334 qtty::Degree
lon()
const {
338 template <
typename F_ = F, std::enable_if_t<frames::has_lon_lat_v<F_>,
int> = 0>
339 qtty::Degree
lat()
const {
364 template <
typename Target>
368 template <
typename Target>
375 template <
typename Target>
396 const double r = dist_.value();
397 const double s =
other.dist_.value();
401 const double a1 = azimuth_.value() *
DEG2RAD;
402 const double p1 = polar_.value() *
DEG2RAD;
415 double d = std::sqrt(
r *
r +
s *
s - 2.0 *
r *
s * dot);
427template <
typename F, std::enable_if_t<frames::has_ra_dec_v<F>,
int> = 0>
429 coordinates::detail::write_frame<F>(os);
430 return os <<
" (ra=" << dir.
ra() <<
", dec=" << dir.
dec() <<
')';
436template <
typename F, std::enable_if_t<frames::has_az_alt_v<F>,
int> = 0>
437inline std::ostream &
operator<<(std::ostream &os,
const Direction<F> &dir) {
438 coordinates::detail::write_frame<F>(os);
439 return os <<
" (az=" << dir.az() <<
", alt=" << dir.alt() <<
')';
445template <
typename F, std::enable_if_t<frames::has_lon_lat_v<F>,
int> = 0>
446inline std::ostream &
operator<<(std::ostream &os,
const Direction<F> &dir) {
447 coordinates::detail::write_frame<F>(os);
448 return os <<
" (lon=" << dir.lon() <<
", lat=" << dir.lat() <<
')';
454template <
typename C,
typename F,
typename U, std::enable_if_t<frames::has_ra_dec_v<F>,
int> = 0>
456 coordinates::detail::write_center_frame<C, F>(os);
457 return os <<
" (ra=" << pos.
ra() <<
", dec=" << pos.
dec() <<
", r=" << pos.
distance() <<
')';
463template <
typename C,
typename F,
typename U, std::enable_if_t<frames::has_az_alt_v<F>,
int> = 0>
464inline std::ostream &
operator<<(std::ostream &os,
const Position<C, F, U> &pos) {
465 coordinates::detail::write_center_frame<C, F>(os);
466 return os <<
" (az=" << pos.az() <<
", alt=" << pos.alt() <<
", r=" << pos.distance() <<
')';
472template <
typename C,
typename F,
typename U, std::enable_if_t<frames::has_lon_lat_v<F>,
int> = 0>
473inline std::ostream &
operator<<(std::ostream &os,
const Position<C, F, U> &pos) {
474 coordinates::detail::write_center_frame<C, F>(os);
475 return os <<
" (lon=" << pos.lon() <<
", lat=" << pos.lat() <<
", r=" << pos.distance() <<
')';
constexpr double pi
Circle constant pi (radians per half-turn).
std::ostream & operator<<(std::ostream &os, const Direction< F > &dir)
Stream operator for Direction with RA/Dec frames.
tempoch::EncodedTime< Scale, Format > Time
void check_status(siderust_status_t status, const char *operation)
Shared helpers for human-readable coordinate stream output.
Geodetic position (WGS84 ellipsoid).
A unit-vector direction in Cartesian form, compile-time frame-tagged.
A 3D Cartesian position, compile-time tagged by center, frame, unit.
SFINAE helper: every frame tag must provide these static members.
A direction on the celestial sphere, compile-time tagged by frame.
std::enable_if_t< frames::has_horizontal_transform_v< F_ >, Direction< frames::Horizontal > > to_horizontal_with(const Time< TT, JD > &jd, const Geodetic &observer, const AstroContext &ctx) const
Transform to the horizontal frame with an explicit context.
static constexpr siderust_frame_t frame_id()
Direction(qtty::Degree azimuth, qtty::Degree polar)
qtty::Degree latitude() const
cartesian::Direction< F > to_cartesian() const
Convert this spherical direction to a Cartesian unit vector.
static constexpr const char * frame_name()
qtty::Degree altitude() const
std::enable_if_t< frames::has_frame_transform_v< F, Target >, Direction< Target > > to_frame_with(const Time< TT, JD > &jd, const AstroContext &ctx) const
Transform to a different reference frame with an explicit context.
qtty::Degree angular_separation(const Direction &other) const
Angular separation between this direction and another.
auto to(const Time< TT, JD > &jd) const -> decltype(this->template to_frame< Target >(jd))
Shorthand: .to<Target>(jd) (calls to_frame).
siderust_spherical_dir_t to_c() const
std::enable_if_t< frames::has_horizontal_transform_v< F_ >, Direction< frames::Horizontal > > to_horizontal(const Time< TT, JD > &jd, const Geodetic &observer) const
Transform to the horizontal (alt-az) frame.
std::enable_if_t< frames::has_horizontal_transform_v< F_ >, Direction< frames::Horizontal > > to_horizontal_precise(const Time< TT, JD > &jd_tt, const Time< UT1, JD > &jd_ut1, const Geodetic &observer) const
High-precision horizontal transform with explicit TT and UT1 epochs.
std::enable_if_t< frames::has_frame_transform_v< F, Target >, Direction< Target > > to_frame(const Time< TT, JD > &jd) const
Transform to a different reference frame.
qtty::Degree longitude() const
static Direction from_c(const siderust_spherical_dir_t &c)
A spherical position (direction + distance), compile-time tagged.
cartesian::Position< C, F, U > to_cartesian() const
Convert this spherical position to a cartesian Position<C,F,U>.
static constexpr siderust_center_t center_id()
Direction< F > direction() const
Extract the direction component.
static constexpr siderust_frame_t frame_id()
Position(qtty::Degree azimuth, qtty::Degree polar, U distance)
Position(const Direction< F > &dir, U distance)
auto to(const Time< TT, JD > &jd) const -> decltype(this->template to_frame< Target >(jd))
Shorthand: .to<Target>(jd) (calls to_frame).
std::enable_if_t< frames::has_frame_transform_v< F, Target >, Position< C, Target, U > > to_frame_with(const Time< TT, JD > &jd, const AstroContext &ctx) const
U distance_to(const Position &other) const
qtty::Degree angular_separation(const Position &other) const
Angular separation between this position's direction and another's.
std::enable_if_t< frames::has_frame_transform_v< F, Target >, Position< C, Target, U > > to_frame(const Time< TT, JD > &jd) const
Transform this position to a different reference frame (same center).