58template <
typename T>
struct is_spherical_direction : std::false_type {};
60template <
typename F>
struct is_spherical_direction<spherical::Direction<F>> : std::true_type {};
63inline constexpr bool is_spherical_direction_v = is_spherical_direction<T>::value;
66template <
typename T>
struct spherical_direction_frame;
68template <
typename F>
struct spherical_direction_frame<spherical::Direction<F>> {
73using spherical_direction_frame_t =
typename spherical_direction_frame<T>::type;
114 static_assert(detail::is_spherical_direction_v<C>,
"Target<C>: C must be a specialisation of "
115 "siderust::spherical::Direction<F>");
117 using Frame = detail::spherical_direction_frame_t<C>;
119 static_assert(frames::has_frame_transform_v<Frame, frames::ICRS>,
120 "Target<C>: frame F must support a transform to ICRS "
121 "(frames::has_frame_transform_v<F, frames::ICRS> must be true). "
122 "Supported frames: ICRS, ICRF, EquatorialMeanJ2000, "
123 "EquatorialMeanOfDate, EquatorialTrueOfDate, EclipticMeanJ2000.");
143 std::string label =
"")
144 : m_dir_(dir), m_epoch_(
epoch), label_(std::move(label)) {
146 if constexpr (std::is_same_v<Frame, frames::ICRS>) {
149 m_icrs_ = dir.template to_frame<frames::ICRS>(
epoch);
151 SiderustGenericTarget *h =
nullptr;
152 check_status(siderust_generic_target_create_icrs(m_icrs_.
ra().value(), m_icrs_.
dec().value(),
160 siderust_generic_target_free(handle_);
167 : m_dir_(std::move(other.m_dir_)), m_epoch_(other.m_epoch_), m_icrs_(other.m_icrs_),
168 label_(std::move(other.label_)), handle_(other.handle_) {
169 other.handle_ =
nullptr;
174 if (
this != &other) {
176 siderust_generic_target_free(handle_);
178 m_dir_ = std::move(other.m_dir_);
179 m_epoch_ = other.m_epoch_;
180 m_icrs_ = other.m_icrs_;
181 label_ = std::move(other.label_);
182 handle_ = other.handle_;
183 other.handle_ =
nullptr;
202 std::string
name()
const override {
205 std::ostringstream ss;
206 ss <<
"Direction(" << m_icrs_.
ra().value() <<
"\xc2\xb0, " << m_icrs_.
dec().value()
226 template <
typename F_ = Frame, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
227 qtty::Degree
ra()
const {
232 template <
typename F_ = Frame, std::enable_if_t<frames::has_ra_dec_v<F_>,
int> = 0>
233 qtty::Degree
dec()
const {
250 "Target::altitude_at");
251 return qtty::Radian(out).to<qtty::Degree>();
258 qtty::Degree threshold,
260 tempoch_period_mjd_t *ptr =
nullptr;
263 window.c_inner(), threshold.value(), opts.to_c(), &ptr,
265 "Target::above_threshold");
266 return detail_periods_from_c(ptr, count);
273 qtty::Degree threshold,
275 tempoch_period_mjd_t *ptr =
nullptr;
278 window.c_inner(), threshold.value(), opts.to_c(), &ptr,
280 "Target::below_threshold");
281 return detail_periods_from_c(ptr, count);
288 qtty::Degree threshold,
290 siderust_crossing_event_t *ptr =
nullptr;
293 window.c_inner(), threshold.value(), opts.to_c(), &ptr, &count),
294 "Target::crossings");
303 siderust_culmination_event_t *ptr =
nullptr;
306 window.c_inner(), opts.to_c(), &ptr, &count),
307 "Target::culminations");
322 "Target::azimuth_at");
323 return qtty::Degree(out);
329 std::vector<AzimuthCrossingEvent>
332 siderust_azimuth_crossing_event_t *ptr =
nullptr;
335 obs.
to_c(), window.c_inner(), bearing.value(),
336 opts.to_c(), &ptr, &count),
337 "Target::azimuth_crossings");
342 const SiderustGenericTarget *
c_handle()
const {
return handle_; }
345 SiderustGenericTargetData
data()
const {
346 SiderustGenericTargetData out{};
347 check_status(siderust_generic_target_get_data(handle_, &out),
"DirectionTarget::data");
356 SiderustGenericTarget *handle_ =
nullptr;
359 static std::vector<Period<TT, MJD>> detail_periods_from_c(tempoch_period_mjd_t *ptr,
361 std::vector<Period<TT, MJD>> result;
362 result.reserve(count);
363 for (uintptr_t i = 0; i < count; ++i) {
367 siderust_periods_free(ptr, count);
430 label_(std::move(label)) {
431 SiderustGenericTarget *h =
nullptr;
432 const auto pm = proper_motion_.
to_c();
433 check_status(siderust_generic_target_create_icrs_with_pm(
434 position_.
ra().value(), position_.
dec().value(),
epoch.value(),
435 pm.pm_ra_deg_yr, pm.pm_dec_deg_yr, pm.ra_convention, &h),
436 "ProperMotionTarget::ProperMotionTarget");
442 siderust_generic_target_free(handle_);
448 : position_(other.position_), epoch_(other.epoch_), proper_motion_(other.proper_motion_),
449 label_(std::move(other.label_)), handle_(other.handle_) {
450 other.handle_ =
nullptr;
454 if (
this != &other) {
456 siderust_generic_target_free(handle_);
457 position_ = other.position_;
458 epoch_ = other.epoch_;
459 proper_motion_ = other.proper_motion_;
460 label_ = std::move(other.label_);
461 handle_ = other.handle_;
462 other.handle_ =
nullptr;
472 std::string
name()
const override {
475 SiderustGenericTargetData d{};
476 siderust_generic_target_get_data(handle_, &d);
477 std::ostringstream ss;
478 ss <<
"ProperMotion(" << d.coord.spherical_dir.azimuth_deg <<
"\xc2\xb0, "
479 << d.coord.spherical_dir.polar_deg <<
"\xc2\xb0)";
495 SiderustGenericTargetData
data()
const {
496 SiderustGenericTargetData out{};
497 check_status(siderust_generic_target_get_data(handle_, &out),
"ProperMotionTarget::data");
507 "ProperMotionTarget::altitude_at");
508 return qtty::Radian(out).to<qtty::Degree>();
512 qtty::Degree threshold,
514 tempoch_period_mjd_t *ptr =
nullptr;
517 window.c_inner(), threshold.value(), opts.to_c(), &ptr,
519 "ProperMotionTarget::above_threshold");
520 return detail_periods_from_c(ptr, count);
524 qtty::Degree threshold,
526 tempoch_period_mjd_t *ptr =
nullptr;
529 window.c_inner(), threshold.value(), opts.to_c(), &ptr,
531 "ProperMotionTarget::below_threshold");
532 return detail_periods_from_c(ptr, count);
536 qtty::Degree threshold,
538 siderust_crossing_event_t *ptr =
nullptr;
541 window.c_inner(), threshold.value(), opts.to_c(), &ptr, &count),
542 "ProperMotionTarget::crossings");
548 siderust_culmination_event_t *ptr =
nullptr;
551 window.c_inner(), opts.to_c(), &ptr, &count),
552 "ProperMotionTarget::culminations");
562 "ProperMotionTarget::azimuth_at");
563 return qtty::Degree(out);
566 std::vector<AzimuthCrossingEvent>
569 siderust_azimuth_crossing_event_t *ptr =
nullptr;
572 obs.
to_c(), window.c_inner(), bearing.value(),
573 opts.to_c(), &ptr, &count),
574 "ProperMotionTarget::azimuth_crossings");
581 ProperMotion proper_motion_;
583 SiderustGenericTarget *handle_ =
nullptr;
585 static std::vector<Period<TT, MJD>> detail_periods_from_c(tempoch_period_mjd_t *ptr,
587 std::vector<Period<TT, MJD>> result;
588 result.reserve(count);
589 for (uintptr_t i = 0; i < count; ++i) {
591 Period<TT, MJD>(Time<TT, MJD>(ptr[i].start_mjd), Time<TT, MJD>(ptr[i].end_mjd)));
593 siderust_periods_free(ptr, count);
Altitude computations for Sun, Moon, stars, and arbitrary ICRS directions.
Azimuth computations for Sun, Moon, stars, and arbitrary ICRS directions.
Fixed celestial direction target — a Target for a specific sky position.
SiderustGenericTargetData data() const
Raw coordinate payload stored in the FFI handle.
DirectionTarget(DirectionTarget &&other) noexcept
Move constructor.
qtty::Degree azimuth_at(const Geodetic &obs, const Time< TT, MJD > &mjd) const override
Compute azimuth (degrees, N-clockwise) at a given Time<TT, MJD> instant.
DirectionTarget & operator=(DirectionTarget &&other) noexcept
Move assignment.
std::vector< Period< TT, MJD > > above_threshold(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find periods when the target is above a threshold altitude.
std::vector< CulminationEvent > culminations(const Geodetic &obs, const Period< TT, MJD > &window, const SearchOptions &opts={}) const override
Find culmination (local altitude extremum) events.
std::vector< AzimuthCrossingEvent > azimuth_crossings(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree bearing, const SearchOptions &opts={}) const override
Find epochs when the target crosses a given azimuth bearing.
DirectionTarget(const DirectionTarget &)=delete
std::string name() const override
Human-readable name for this direction target.
DirectionTarget & operator=(const DirectionTarget &)=delete
std::vector< CrossingEvent > crossings(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find threshold-crossing events (rising / setting).
const SiderustGenericTarget * c_handle() const
Access the underlying C handle (advanced use).
std::vector< Period< TT, MJD > > below_threshold(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find periods when the target is below a threshold altitude.
const spherical::direction::ICRS & icrs_direction() const
qtty::Degree dec() const
Declination — only available for equatorial frames (RA/Dec).
Time< TT, JD > epoch() const
Epoch of the coordinate.
qtty::Degree ra() const
Right ascension — only available for equatorial frames (RA/Dec).
DirectionTarget(C dir, Time< TT, JD > epoch=Time< TT, JD >::J2000(), std::string label="")
Construct from a strongly-typed spherical direction.
qtty::Degree altitude_at(const Geodetic &obs, const Time< TT, MJD > &mjd) const override
Compute altitude (degrees) at a given Time<TT, MJD> instant.
const C & direction() const
The original typed direction as supplied at construction.
ICRS target with proper motion (RAII wrapper over the FFI handle).
std::vector< Period< TT, MJD > > above_threshold(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find periods when the object is above a threshold altitude.
ProperMotionTarget(spherical::direction::ICRS position, Time< TT, JD > epoch, ProperMotion proper_motion, std::string label="")
Construct a proper-motion target from an ICRS direction and typed rates.
SiderustGenericTargetData data() const
Raw coordinate payload stored in the FFI handle.
ProperMotionTarget(ProperMotionTarget &&other) noexcept
Time< TT, JD > epoch() const
Coordinate epoch.
ProperMotionTarget & operator=(ProperMotionTarget &&other) noexcept
std::string name() const override
Human-readable name for this target (e.g. "Sun", "Vega", "ICRS(279.2°, 38.8°)").
std::vector< AzimuthCrossingEvent > azimuth_crossings(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree bearing, const SearchOptions &opts={}) const override
Find epochs when the object crosses a given azimuth bearing.
std::vector< CrossingEvent > crossings(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find threshold-crossing events (rising / setting).
qtty::Degree azimuth_at(const Geodetic &obs, const Time< TT, MJD > &mjd) const override
Compute azimuth (degrees, N-clockwise) at a given Time<TT, MJD> instant.
const spherical::direction::ICRS & position() const
ICRS position at the coordinate epoch.
ProperMotionTarget(const ProperMotionTarget &)=delete
std::vector< CulminationEvent > culminations(const Geodetic &obs, const Period< TT, MJD > &window, const SearchOptions &opts={}) const override
Find culmination (local altitude extremum) events.
std::vector< Period< TT, MJD > > below_threshold(const Geodetic &obs, const Period< TT, MJD > &window, qtty::Degree threshold, const SearchOptions &opts={}) const override
Find periods when the object is below a threshold altitude.
ProperMotionTarget & operator=(const ProperMotionTarget &)=delete
qtty::Degree altitude_at(const Geodetic &obs, const Time< TT, MJD > &mjd) const override
Compute altitude (degrees) at a given Time<TT, MJD> instant.
const ProperMotion & proper_motion() const
Proper motion rates.
Abstract base for any celestial object that can be tracked from an observer location.
Coordinate module umbrella.
Error handling and utility base for the siderust C++ wrapper.
std::vector< CrossingEvent > crossings_from_c(siderust_crossing_event_t *ptr, uintptr_t count)
siderust_subject_t make_generic_target_subject(const SiderustGenericTarget *h)
Build a siderust_subject_t for a generic target opaque handle.
std::vector< CulminationEvent > culminations_from_c(siderust_culmination_event_t *ptr, uintptr_t count)
std::vector< AzimuthCrossingEvent > az_crossings_from_c(siderust_azimuth_crossing_event_t *ptr, uintptr_t count)
Direction< frames::ICRS > ICRS
tempoch::EncodedTime< Scale, Format > Time
void check_status(siderust_status_t status, const char *operation)
tempoch::Period< Time< Scale, Format > > Period
Geodetic position (WGS84 ellipsoid).
siderust_geodetic_t to_c() const
Convert to C FFI struct.
Proper motion for a star (equatorial).
siderust_proper_motion_t to_c() const
Options for altitude search algorithms.
A direction on the celestial sphere, compile-time tagged by frame.
Public siderust time tags and typed time/period aliases.
Abstract base class for all celestial targets.