16#include <qtty/qtty.hpp>
27template <
typename C,
typename F,
typename U>
struct Position;
54 qtty::Degree azimuth_;
58 Direction() : azimuth_(qtty::Degree(0)), polar_(qtty::Degree(0)) {}
60 Direction(qtty::Degree azimuth, qtty::Degree polar) : azimuth_(azimuth), polar_(polar) {}
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>
129 siderust_spherical_dir_t
to_c()
const {
return {polar_.value(), azimuth_.value(),
frame_id()}; }
132 return Direction(qtty::Degree(c.azimuth_deg), qtty::Degree(c.polar_deg));
147 const double az1 = azimuth_.value() * DEG2RAD;
148 const double po1 = polar_.value() * DEG2RAD;
149 const double az2 = other.azimuth_.value() * DEG2RAD;
150 const double po2 = other.polar_.value() * DEG2RAD;
152 std::cos(po1) * std::sin(po2) - std::sin(po1) * std::cos(po2) * std::cos(az2 - az1);
153 const double y = std::cos(po2) * std::sin(az2 - az1);
155 std::sin(po1) * std::sin(po2) + std::cos(po1) * std::cos(po2) * std::cos(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>) {
173 siderust_spherical_dir_t out;
177 "Direction::to_frame");
185 template <
typename Target>
188 if constexpr (std::is_same_v<F, Target>) {
191 siderust_spherical_dir_t out;
193 check_status(siderust_spherical_dir_transform_frame_with_context(
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>
229 siderust_spherical_dir_t out;
230 check_status(siderust_spherical_dir_to_horizontal(polar_.value(), azimuth_.value(),
232 observer.
to_c(), &out),
233 "Direction::to_horizontal");
240 template <
typename F_ = F>
244 siderust_spherical_dir_t out;
246 check_status(siderust_spherical_dir_to_horizontal_precise_with_context(
248 jd.value(), observer.
to_c(), fctx.
get(), &out),
249 "Direction::to_horizontal_with");
264 template <
typename F_ = F>
268 siderust_spherical_dir_t out;
269 check_status(siderust_spherical_dir_to_horizontal_precise(
271 jd_tt.value(), jd_ut1.value(), observer.
to_c(), &out),
272 "Direction::to_horizontal_precise");
287template <
typename C,
typename F,
typename U = qtty::Meter>
struct Position {
292 qtty::Degree azimuth_;
298 : azimuth_(azimuth), polar_(polar), dist_(
distance) {}
301 : azimuth_(dir.azimuth()), polar_(dir.polar()), dist_(
distance) {}
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;
403 const double a2 = other.azimuth_.value() * DEG2RAD;
404 const double p2 = other.polar_.value() * DEG2RAD;
407 double cos_p1 = std::cos(p1);
408 double cos_p2 = std::cos(p2);
409 double dot = cos_p1 * cos_p2 * std::cos(a1 - a2) + std::sin(p1) * std::sin(p2);
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>
430 return os <<
" (ra=" << dir.
ra() <<
", dec=" << dir.
dec() <<
')';
436template <
typename F, std::enable_if_t<frames::has_az_alt_v<F>,
int> = 0>
439 return os <<
" (az=" << dir.
az() <<
", alt=" << dir.
alt() <<
')';
445template <
typename F, std::enable_if_t<frames::has_lon_lat_v<F>,
int> = 0>
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>
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>
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>
475 return os <<
" (lon=" << pos.
lon() <<
", lat=" << pos.
lat() <<
", r=" << pos.
distance() <<
')';
Thin C++ context for selecting Earth-orientation / nutation models.
Zero-sized reference-center tag types mirroring Rust's centers module.
const siderust_context_t * get() const
Portable mathematical constants (C++17, no platform macros).
Zero-sized reference-frame tag types mirroring Rust's affn::frames.
WGS84 geodetic coordinate type.
constexpr bool is_center_v
constexpr double pi
Circle constant pi (radians per half-turn).
void write_frame(std::ostream &os)
void write_center_frame(std::ostream &os)
constexpr bool is_frame_v
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).
siderust_geodetic_t to_c() const
Convert to C FFI struct.
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).
Public siderust time tags and typed time/period aliases.