mountcontrol/mcc/mcc_generics.h
Timur A. Fatkhullin 6c10c6b6ff add mcc directory
2025-08-18 02:10:43 +03:00

407 lines
14 KiB
C++

#pragma once
/* MOUNT CONTROL COMPONENTS LIBRARY */
/* SOME LIBRARY-WIDE DECLARATIONS */
#include <chrono>
#include <concepts>
#include "mcc_traits.h"
namespace mcc
{
// mount construction type (only the most common ones)
enum class MccMountType : uint8_t { GERMAN_TYPE, FORK_TYPE, CROSSAXIS_TYPE, ALTAZ_TYPE };
enum MccCoordPairKind : size_t {
COORDS_KIND_GENERIC,
COORDS_KIND_RADEC_ICRS,
COORDS_KIND_RADEC_APP,
COORDS_KIND_HADEC_APP,
COORDS_KIND_AZZD,
COORDS_KIND_AZALT,
COORDS_KIND_XY,
COORDS_KIND_LATLON
};
/* FLOATING-POINT LIKE CLASS CONCEPT */
template <typename T>
concept mcc_fp_type_like_c =
std::floating_point<T> ||
(std::convertible_to<T, double> && std::constructible_from<T, double> && std::default_initializable<T>);
/* ANGLE REPRESENTATION CLASS CONCEPT */
template <typename T>
concept mcc_angle_c = mcc_fp_type_like_c<T> && requires(T v, double vd) {
{ v + v } -> std::same_as<T>;
{ v - v } -> std::same_as<T>;
{ v += v } -> std::same_as<T&>;
{ v -= v } -> std::same_as<T&>;
{ v * vd } -> std::same_as<T>;
{ v / vd } -> std::same_as<T>;
};
/* TIME POINT CLASS CONCEPT */
/*
* USE OF STL std::chrono::time_point
*/
template <typename T>
concept mcc_time_point_c = requires(T t) { []<typename CT, typename DT>(std::chrono::time_point<CT, DT>) {}(t); };
/* JULIAN DAY CLASS CONCEPT */
template <typename T>
concept mcc_julday_c = mcc_fp_type_like_c<T> && requires(const T v) {
// comparison operators
v <=> v;
};
/* ERROR CLASS CONCEPT */
template <typename T>
concept mcc_error_c = std::convertible_to<T, bool> || requires(const T t) {
{ t.operator bool() };
};
/* ATMOSPHERIC REFRACTION MODEL CLASS CONCEPT */
template <typename T>
concept mcc_refract_model_c = requires(const T t_const) {
{ t_const.name() } -> std::formattable<char>;
};
/* CELESTIAL POINT WITH A PAIR OF COORDINATES CLASS CONCEPT */
template <typename T>
concept mcc_celestial_point_c = requires(T t) {
requires std::same_as<decltype(t.pair_kind), MccCoordPairKind>; // type of given coordinate pair
requires mcc_time_point_c<decltype(t.time_point)>; // time point for given coordinates
requires mcc_angle_c<decltype(t.X)>; // co-longitude (X-axis)
requires mcc_angle_c<decltype(t.Y)>; // co-latitude (Y-axis)
};
/* CELESTIAL POINT WITH APPARENT EQUATORIAL AND HORIZONTAL CLASS CONCEPT */
template <typename T>
concept mcc_eqt_hrz_coord_c = mcc_celestial_point_c<T> && requires(T t) {
requires mcc_angle_c<decltype(t.RA_APP)>; // right ascension
requires mcc_angle_c<decltype(t.DEC_APP)>; // declination
requires mcc_angle_c<decltype(t.HA)>; // hour angle
requires mcc_angle_c<decltype(t.AZ)>; // azimuth
requires mcc_angle_c<decltype(t.ZD)>; // zenithal distance
requires mcc_angle_c<decltype(t.ALT)>; // altitude
};
/* CELESTIAL COORDINATES TRANSFORMATION ENGINE */
template <mcc_error_c RetT>
struct mcc_CCTE_interface_t {
virtual ~mcc_CCTE_interface_t() = default;
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT timepointToJulday(this SelfT&& self, mcc_time_point_c auto tp, mcc_julday_c auto* julday)
{
return std::forward<SelfT>(self).timepointToJulday(std::move(tp), julday);
}
// APPARENT SIDERAL TIME
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT timepointToAppSideral(this SelfT&& self, mcc_time_point_c auto tp, mcc_angle_c auto* st, bool islocal = false)
{
return std::forward<SelfT>(self).timepointToAppSideral(std::move(tp), st, islocal);
}
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT transformCoordinates(this SelfT&& self, mcc_celestial_point_c auto from_pt, mcc_celestial_point_c auto* to_pt)
{
return std::forward<SelfT>(self).transformCoordinates(std::move(from_pt), to_pt);
}
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT transformCoordinates(this SelfT&& self, mcc_celestial_point_c auto from_pt, mcc_eqt_hrz_coord_c auto* to_pt)
{
return std::forward<SelfT>(self).transformCoordinates(std::move(from_pt), to_pt);
}
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT parallacticAngle(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_angle_c auto* pa)
{
return std::forward<SelfT>(self).parallacticAngle(std::move(pt), pa);
}
template <std::derived_from<mcc_CCTE_interface_t> SelfT>
RetT refractionCorrection(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_angle_c auto* dZ)
{
return std::forward<SelfT>(self).refractionCoeff(std::move(pt), dZ);
}
protected:
mcc_CCTE_interface_t() = default;
};
template <typename T>
concept mcc_ast_engine_c =
std::derived_from<T, mcc_CCTE_interface_t<typename T::error_t>> && requires(const T t_const, T t) {
{ t_const.name() } -> std::formattable<char>;
requires mcc_refract_model_c<typename T::refract_model_t>;
{ t.refractionModel(std::declval<typename T::refract_model_t*>()) } -> std::same_as<typename T::error_t>;
};
/* MOUNT TELEMETRY DATA CLASS CONCEPT */
template <typename T>
concept mcc_pointing_target_coord_c = mcc_eqt_hrz_coord_c<T> && requires(T t) {
requires mcc_angle_c<decltype(t.RA_ICRS)>; // ICRS right ascention
requires mcc_angle_c<decltype(t.DEC_ICRS)>; // ICRS declination
};
template <typename T>
concept mcc_telemetry_data_c = mcc_eqt_hrz_coord_c<T> && requires(T t) {
// target target coordinates
requires mcc_pointing_target_coord_c<decltype(t.target)>;
// t.X and t.Y (from mcc_celestial_point_c) are encoder coordinates
// t.* from mcc_eqt_hrz_coord_c are apparent mount pointing coordinates
requires mcc_angle_c<decltype(t.speedX)>; // speed along X from hardware encoder
requires mcc_angle_c<decltype(t.speedY)>; // speed along Y from hardware encoder
// corrections to transform hardware encoder coordinates to apparent celestial ones
requires mcc_angle_c<decltype(t.pcmX)>; // PCM correction along X-axis
requires mcc_angle_c<decltype(t.pcmY)>; // PCM correction along Y-axis
// atmospheric refraction correction for current zenithal distance
requires mcc_angle_c<decltype(t.refCorr)>; // for current .ZD
};
/* MOUNT TELEMETRY MANAGER CLASS CONCEPT */
template <mcc_error_c RetT>
struct mcc_telemetry_interface_t {
virtual ~mcc_telemetry_interface_t() = default;
template <std::derived_from<mcc_telemetry_interface_t> SelfT>
RetT telemetryData(this SelfT&& self, mcc_telemetry_data_c auto* data)
{
return std::forward<SelfT>(self).telemetryData(data);
}
template <std::derived_from<mcc_telemetry_interface_t> SelfT>
RetT setPointingTarget(this SelfT&& self, mcc_celestial_point_c auto pt)
{
return std::forward<SelfT>(self).telemetryData(std::move(pt));
}
protected:
mcc_telemetry_interface_t() = default;
};
template <typename T>
concept mcc_telemetry_c = std::derived_from<T, mcc_telemetry_interface_t<typename T::error_t>>;
/* POINTING CORRECTION MODEL CLASS CONCEPT */
template <typename T>
concept mcc_PCM_result_c = requires(T t) {
requires mcc_angle_c<decltype(t.dx)>;
requires mcc_angle_c<decltype(t.dy)>;
};
template <mcc_error_c RetT, mcc_PCM_result_c ResT>
struct mcc_PCM_interface_t {
template <std::derived_from<mcc_PCM_interface_t> SelfT>
RetT computePCM(this SelfT&& self, mcc_celestial_point_c auto pt, ResT* result)
{
return std::forward<SelfT>(self).computePCM(std::move(pt), result);
}
};
template <typename T>
concept mcc_PCM_c =
std::derived_from<T, mcc_PCM_interface_t<typename T::error_t, typename T::pcm_result_t>> && requires {
// the 'T' class must contain static constexpr member of 'MccMountType' type
requires std::same_as<decltype(T::mountType), const MccMountType>;
[]() {
static constexpr MccMountType val = T::mountType;
return val;
}(); // to ensure 'mountType' can be used in compile-time context
};
/* MOUNT HARDWARE ABSTRACTION CLASS CONCEPT */
template <typename T>
concept mcc_hardware_c = requires(T t, const T t_const) {
typename T::error_t;
{ t_const.name() } -> std::formattable<char>;
// a class that contains at least time point of measurement, coordinates for x,y axes and its moving rates
requires requires(typename T::axes_pos_t pos) {
requires mcc_time_point_c<typename T::time_point_t>; // time point
requires mcc_angle_c<decltype(pos.X)>; // target or current co-longitude coordinate
requires mcc_angle_c<decltype(pos.Y)>; // target or current co-latitude coordinate
requires mcc_angle_c<decltype(pos.speedX)>;
requires mcc_angle_c<decltype(pos.speedY)>;
};
// set positions (angles) of mount axes with given speeds
// NOTE: exact interpretation (or even ignoring) of the given moving speeds is subject of a hardware-class
// implementation.
// e.g. it can be maximal speeds at slewing ramp
{ t.setPos(std::declval<typename T::axes_pos_t>()) } -> std::same_as<typename T::error_t>;
// get current positions and speeds (angles) of mount axes
{ t.getPos(std::declval<typename T::axes_pos_t*>()) } -> std::same_as<typename T::error_t>;
{ t.stop() } -> std::same_as<typename T::error_t>; // stop any moving
{ t.init() } -> std::same_as<typename T::error_t>; // initialize hardware
};
/* PROHIBITED ZONE CLASS CONCEPT */
template <mcc_error_c RetT>
struct mcc_pzone_interface_t {
virtual ~mcc_pzone_interface_t() = default;
template <std::derived_from<mcc_pzone_interface_t> SelfT, typename InputT>
RetT inPZone(this SelfT&& self, InputT coords, bool* result)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).InPZone(std::move(coords), result);
}
template <std::derived_from<mcc_pzone_interface_t> SelfT, typename InputT>
RetT timeToPZone(this SelfT&& self, InputT coords, traits::mcc_time_duration_c auto* res_time)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).timeToPZone(std::move(coords), res_time);
}
template <std::derived_from<mcc_pzone_interface_t> SelfT, typename InputT>
RetT timeFromPZone(this SelfT&& self, InputT coords, traits::mcc_time_duration_c auto* res_time)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).timeFromPZone(std::move(coords), res_time);
}
template <std::derived_from<mcc_pzone_interface_t> SelfT, typename InputT>
RetT intersectPZone(this SelfT&& self, InputT coords, mcc_celestial_point_c auto* point)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>) &&
requires { self.intersectPZone(coords, point); }
{
return std::forward<SelfT>(self).intersectPZone(std::move(coords), point);
}
protected:
mcc_pzone_interface_t() = default;
};
template <typename T>
concept mcc_prohibited_zone_c =
std::derived_from<T, mcc_pzone_interface_t<typename T::error_t>> && requires(const T t_const) {
{ t_const.name() } -> std::formattable<char>;
};
/* PROHIBITED ZONES CONTAINER CLASS CONCEPT */
template <mcc_error_c RetT>
struct mcc_pzone_container_interface_t {
virtual ~mcc_pzone_container_interface_t() = default;
template <std::derived_from<mcc_pzone_container_interface_t> SelfT>
size_t addPZone(this SelfT&& self, mcc_prohibited_zone_c auto zone)
{
return std::forward<SelfT>(self).addPZone(std::move(zone));
}
template <std::derived_from<mcc_pzone_container_interface_t> SelfT>
void clearPZones(this SelfT&& self)
{
return std::forward<SelfT>(self).clearPZones();
}
template <std::derived_from<mcc_pzone_container_interface_t> SelfT>
size_t sizePZones(this SelfT&& self)
{
return std::forward<SelfT>(self).sizePZones();
}
template <std::derived_from<mcc_pzone_container_interface_t> SelfT, typename InputT>
RetT inPZone(this SelfT&& self, InputT coords, std::ranges::output_range<bool> auto* result)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).InPZone(std::move(coords), result);
}
template <std::derived_from<mcc_pzone_container_interface_t> SelfT, typename InputT, traits::mcc_time_duration_c DT>
RetT timeToPZone(this SelfT&& self, InputT coords, std::ranges::output_range<DT> auto* res_time)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).timeToPZone(std::move(coords), res_time);
}
template <std::derived_from<mcc_pzone_container_interface_t> SelfT, typename InputT, traits::mcc_time_duration_c DT>
RetT timeFromPZone(this SelfT&& self, InputT coords, std::ranges::output_range<DT> auto* res_time)
requires(mcc_eqt_hrz_coord_c<InputT> || mcc_celestial_point_c<InputT>)
{
return std::forward<SelfT>(self).timeFromPZone(std::move(coords), res_time);
}
protected:
mcc_pzone_container_interface_t() = default;
};
template <typename T>
concept mcc_pzone_container_c = std::derived_from<T, mcc_pzone_container_interface_t<typename T::error_t>>;
} // namespace mcc