#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* SOME LIBRARY-WIDE DECLARATIONS */ #include #include // #include "mcc_traits.h" #include "mcc_angle.h" #include "mcc_finite_state_machine.h" namespace mcc { static constexpr double mcc_sideral_to_UT1_ratio = 1.002737909350795; // sideral/UT1 // mount construction type (only the most common ones) enum class MccMountType : uint8_t { GERMAN_TYPE, FORK_TYPE, CROSSAXIS_TYPE, ALTAZ_TYPE }; template static constexpr std::string_view MccMountTypeStr = TYPE == MccMountType::GERMAN_TYPE ? "GERMAN" : TYPE == MccMountType::FORK_TYPE ? "FORK" : TYPE == MccMountType::CROSSAXIS_TYPE ? "CROSSAXIS" : TYPE == MccMountType::ALTAZ_TYPE ? "ALTAZ" : "UNKNOWN"; template static constexpr bool mcc_is_equatorial_mount = TYPE == MccMountType::GERMAN_TYPE ? true : TYPE == MccMountType::FORK_TYPE ? true : TYPE == MccMountType::CROSSAXIS_TYPE ? true : TYPE == MccMountType::ALTAZ_TYPE ? false : false; template static constexpr bool mcc_is_altaz_mount = TYPE == MccMountType::GERMAN_TYPE ? false : TYPE == MccMountType::FORK_TYPE ? false : TYPE == MccMountType::CROSSAXIS_TYPE ? false : TYPE == MccMountType::ALTAZ_TYPE ? true : false; static consteval bool mccIsEquatorialMount(const MccMountType type) { return type == MccMountType::GERMAN_TYPE ? true : type == MccMountType::FORK_TYPE ? true : type == MccMountType::CROSSAXIS_TYPE ? true : type == MccMountType::ALTAZ_TYPE ? false : false; }; static consteval bool mccIsAltAzMount(const MccMountType type) { return type == MccMountType::GERMAN_TYPE ? false : type == MccMountType::FORK_TYPE ? false : type == MccMountType::CROSSAXIS_TYPE ? false : type == MccMountType::ALTAZ_TYPE ? true : false; }; enum class MccProhibitedZonePolicy : int { PZ_POLICY_STOP, // stop mount near the zone PZ_POLICY_FLIP // flip mount, e.g., near the meridian, near HA-axis encoder limit switch }; /* GENERIC LOGGER CLASS CONCEPT */ template concept mcc_logger_c = requires(T t, const T t_const) { { t.logError(std::declval()) }; { t.logDebug(std::declval()) }; { t.logWarn(std::declval()) }; { t.logInfo(std::declval()) }; }; struct MccNullLogger { void logError(const std::string&) {} void logDebug(const std::string&) {} void logWarn(const std::string&) {} void logInfo(const std::string&) {} }; /* FLOATING-POINT LIKE CLASS CONCEPT */ template concept mcc_fp_type_like_c = std::floating_point || (std::convertible_to && std::constructible_from && std::default_initializable); /* ANGLE REPRESENTATION CLASS CONCEPT */ template concept mcc_angle_c = mcc_fp_type_like_c && requires(T v, double vd) { // mandatory arithmetic operations { v + v } -> std::same_as; { v - v } -> std::same_as; { v += v } -> std::same_as; { v -= v } -> std::same_as; { vd + v } -> std::same_as; { vd - v } -> std::same_as; { v + vd } -> std::same_as; { v - vd } -> std::same_as; { v += vd } -> std::same_as; { v -= vd } -> std::same_as; { v * vd } -> std::same_as; { v / vd } -> std::same_as; }; /* TIME POINT CLASS CONCEPT */ /* * USE OF STL std::chrono::time_point */ template concept mcc_time_point_c = traits::mcc_systime_c; // concept mcc_time_point_c = requires(T t) { [](std::chrono::time_point) {}(t); }; template static constexpr void mcc_tp2tp(const T1& from_tp1, T2& to_tp) { to_tp = std::chrono::time_point_cast(from_tp1); } /* JULIAN DAY CLASS CONCEPT */ template concept mcc_julday_c = mcc_fp_type_like_c && requires(const T v) { // modified Julian Day { v.MJD() } -> std::convertible_to; // comparison operators v <=> v; }; /* ERROR CLASS CONCEPT */ template concept mcc_error_c = std::default_initializable && (std::convertible_to || requires(const T t) { { t.operator bool() }; (bool)T() == false; // default constucted value must be a "non-error"! }); template static constexpr ErrT mcc_deduce_error(const DErrT& err, const ErrT& default_err) { if constexpr (std::same_as) { return err; } else { return default_err; } } template static constexpr std::error_code mcc_deduce_error_code(const DErrT& err, const ErrT& default_err) requires(std::is_error_code_enum_v || std::same_as) { if constexpr (std::is_error_code_enum_v || std::same_as) { return err; } else { return default_err; } } /* ATMOSPHERIC REFRACTION MODEL CLASS CONCEPT */ template concept mcc_refract_model_c = requires(const T t_const) { { t_const.name() } -> std::formattable; }; /* CELESTIAL POINT WITH A PAIR OF COORDINATES CLASS CONCEPT */ template concept mcc_celestial_point_c = requires(T t) { requires std::same_as, MccCoordPairKind>; // type of given coordinate pair (it may be even static constexpr value) requires mcc_time_point_c; // time point for given coordinates requires mcc_angle_c; // co-longitude (X-axis) requires mcc_angle_c; // co-latitude (Y-axis) }; static constexpr void mcc_copy_celestial_point(mcc_celestial_point_c auto const& from_pt, mcc_celestial_point_c auto* to_pt) { if (to_pt == nullptr) { return; } using from_pt_t = std::remove_cvref_t; using to_pt_t = std::remove_cvref_t; if constexpr (std::derived_from && std::copyable) { *to_pt = from_pt; return; } to_pt->pair_kind = from_pt.pair_kind; to_pt->time_point = std::chrono::time_point_casttime_point)::duration>(from_pt.time_point); to_pt->X = (double)from_pt.X; to_pt->Y = (double)from_pt.Y; } /* CELESTIAL POINT WITH APPARENT EQUATORIAL AND HORIZONTAL CLASS CONCEPT */ template concept mcc_eqt_hrz_coord_c = mcc_celestial_point_c && requires(T t) { requires mcc_angle_c; // right ascension requires mcc_angle_c; // declination requires mcc_angle_c; // hour angle requires mcc_angle_c; // azimuth (NOTE: ASSUMING THE AZINUTH IS COUNTED FROM THE SOUTH THROUGH THE // WEST!!!) requires mcc_angle_c; // zenithal distance requires mcc_angle_c; // altitude }; static constexpr void mcc_copy_eqt_hrz_coord(mcc_eqt_hrz_coord_c auto const& from_pt, mcc_eqt_hrz_coord_c auto* to_pt) { if (to_pt == nullptr) { return; } using from_pt_t = std::remove_cvref_t; using to_pt_t = std::remove_cvref_t; if constexpr (std::derived_from && std::copyable) { *to_pt = from_pt; return; } to_pt->pair_kind = from_pt.pair_kind; to_pt->time_point = std::chrono::time_point_casttime_point)::duration>(from_pt.time_point); to_pt->X = (double)from_pt.X; to_pt->Y = (double)from_pt.Y; to_pt->RA_APP = (double)from_pt.RA_APP; to_pt->DEC_APP = (double)from_pt.DEC_APP; to_pt->HA = (double)from_pt.HA; to_pt->AZ = (double)from_pt.AZ; to_pt->ZD = (double)from_pt.ZD; to_pt->ALT = (double)from_pt.ALT; } // nullptr_t or pointer to celestial/equatorial and horizontal coordinates class template concept mcc_coord_pointer_or_nullptr = std::is_null_pointer_v || (std::is_pointer_v> && (mcc_celestial_point_c>> || mcc_eqt_hrz_coord_c>>)); /* CELESTIAL COORDINATES TRANSFORMATION ENGINE */ template struct mcc_CCTE_interface_t { virtual ~mcc_CCTE_interface_t() = default; template SelfT> RetT timepointToJulday(this SelfT&& self, mcc_time_point_c auto tp, mcc_julday_c auto* julday) { return std::forward(self).timepointToJulday(std::move(tp), julday); } // APPARENT SIDERAL TIME template SelfT> RetT timepointToAppSideral(this SelfT&& self, mcc_time_point_c auto tp, mcc_angle_c auto* st, bool islocal = false) { return std::forward(self).timepointToAppSideral(std::move(tp), st, islocal); } template SelfT> RetT juldayToAppSideral(this SelfT&& self, mcc_julday_c auto jd, mcc_angle_c auto* st, bool islocal = false) { return std::forward(self).timepointToAppSideral(std::move(jd), st, islocal); } // NOTE: ASSUMING THE AZINUTH IS COUNTED FROM THE SOUTH THROUGH THE WEST!!! template SelfT> RetT transformCoordinates(this SelfT&& self, mcc_celestial_point_c auto from_pt, mcc_celestial_point_c auto* to_pt) { return std::forward(self).transformCoordinates(std::move(from_pt), to_pt); } // NOTE: ASSUMING THE AZIMUTH IS COUNTED FROM THE SOUTH THROUGH THE WEST!!! template SelfT> RetT transformCoordinates(this SelfT&& self, mcc_celestial_point_c auto from_pt, mcc_eqt_hrz_coord_c auto* to_pt) { return std::forward(self).transformCoordinates(std::move(from_pt), to_pt); } template SelfT> RetT parallacticAngle(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_angle_c auto* pa) { return std::forward(self).parallacticAngle(std::move(pt), pa); } template SelfT> RetT refractionCorrection(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_angle_c auto* dZ) { return std::forward(self).refractionCoeff(std::move(pt), dZ); } protected: mcc_CCTE_interface_t() = default; }; template concept mcc_ccte_c = std::derived_from> && requires(const T t_const, T t) { { t_const.nameCCTE() } -> std::formattable; requires mcc_refract_model_c; { t.refractionModel(std::declval()) } -> std::same_as; }; /* POINTING CORRECTION MODEL CLASS CONCEPT */ template concept mcc_PCM_result_c = requires(T t) { requires mcc_angle_c; requires mcc_angle_c; }; template struct mcc_PCM_interface_t { virtual ~mcc_PCM_interface_t() = default; // ignore app_pt->pair_kind and time points!!! template SelfT> RetT computePCM(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_PCM_result_c auto* result, mcc_celestial_point_c auto* app_pt) { return std::forward(self).computePCM(std::move(pt), result, app_pt); } // for equatorial mounts the method must compute: // app_pt->HA = pt.X + result->pcmX // app_pt->DEC_APP = pt.Y + result->pcmY // for alt-azimuthal: // app_pt->AZ = pt.X + result->pcmX // app_pt->ZD = pt.Y + result->pcmY template SelfT> RetT computePCM(this SelfT&& self, mcc_celestial_point_c auto pt, mcc_PCM_result_c auto* result, mcc_eqt_hrz_coord_c auto* app_pt) { return std::forward(self).computePCM(std::move(pt), result, app_pt); } template SelfT> RetT computeInversePCM(this SelfT&& self, mcc_celestial_point_c auto app_pt, mcc_PCM_result_c auto* inv_result, mcc_celestial_point_c auto* hw_pt) { return std::forward(self).computePCM(std::move(app_pt), inv_result, hw_pt); } // NOTE: for computation of the corrections the method must use of app_pt.X and app_pt.Y // // for equatorial mounts the method must compute: // hw_pt->X = app_pt.HA + inv_result.pcmX // hw_pt->Y = app_pt.DEC_APP + inv_result.pcmY // and inputs for the corrections computing are app_pt.HA and app_pt.DEC_APP // for alt-azimuthal: // hw_pt->X = app_pt.AZ + inv_result.pcmX // hw_pt->Y = app_pt.ZD + inv_result.pcmY // and inputs for the corrections computing are app_pt.ZA and app_pt.ZD template SelfT> RetT computeInversePCM(this SelfT&& self, mcc_eqt_hrz_coord_c auto app_pt, mcc_PCM_result_c auto* inv_result, mcc_celestial_point_c auto* hw_pt) { return std::forward(self).computePCM(std::move(app_pt), inv_result, hw_pt); } protected: mcc_PCM_interface_t() = default; }; template concept mcc_PCM_c = std::derived_from> && requires { // the 'T' class must contain static constexpr member of 'MccMountType' type requires std::same_as; []() { static constexpr MccMountType val = T::mountType; return val; }(); // to ensure 'mountType' can be used in compile-time context }; /* MOUNT HARDWARE ABSTRACTION CLASS CONCEPT */ template concept mcc_hardware_c = requires(T t, const T t_const) { requires mcc_error_c; { t_const.hardwareName() } -> std::formattable; // the 'T' class must contain static constexpr member of 'MccMountType' type // requires std::same_as; // []() { // static constexpr MccMountType val = T::mountType; // return val; // }(); // to ensure 'mountType' can be used in compile-time context // a type that defines at least HW_MOVE_ERROR, HW_MOVE_STOPPED, HW_MOVE_SLEWING, HW_MOVE_ADJUSTING, HW_MOVE_TRACKING // and HW_MOVE_GUIDING compile-time constants. The main purpose of this type is a // possible tunning of hardware hardwareSetState-related commands and detect stop-state // // e.g. an implementations can be as follows: // enum class hardware_moving_state_t: int {HW_MOVE_ERROR = -1, HW_MOVE_STOPPED = 0, HW_MOVE_SLEWING, // HW_MOVE_ADJUSTING, HW_MOVE_TRACKING, HW_MOVE_GUIDING} // // struct hardware_moving_state_t { // uint16_t HW_MOVE_STOPPED = 0; // uint16_t HW_MOVE_SLEWING = 111; // uint16_t HW_MOVE_ADJUSTING = 222; // uint16_t HW_MOVE_TRACKING = 333; // uint16_t HW_MOVE_GUIDING = 444; // uint16_t HW_MOVE_ERROR = 555; // } requires requires(typename T::hardware_moving_state_t type) { []() { // mount axes were stopped static constexpr auto v0 = T::hardware_moving_state_t::HW_MOVE_STOPPED; // hardware was asked for slewing (move to given celestial point) static constexpr auto v1 = T::hardware_moving_state_t::HW_MOVE_SLEWING; // hardware was asked for adjusting after slewing // (adjusting actual mount position to align with target celestial point at the end of slewing process) static constexpr auto v2 = T::hardware_moving_state_t::HW_MOVE_ADJUSTING; // hardware was asked for tracking (track target celestial point) static constexpr auto v3 = T::hardware_moving_state_t::HW_MOVE_TRACKING; // hardware was asked for guiding // (small corrections to align actual mount position with target celestial point) static constexpr auto v4 = T::hardware_moving_state_t::HW_MOVE_GUIDING; // to detect possible hardware error static constexpr auto v5 = T::hardware_moving_state_t::HW_MOVE_ERROR; }(); }; // a class that contains at least time point of measurement, coordinates for x,y axes, // its moving rates and moving type requires mcc_celestial_point_c && requires(typename T::hardware_state_t state) { // requires mcc_time_point_c; // time point // requires mcc_angle_c; // target or current co-longitude coordinate // requires mcc_angle_c; // target or current co-latitude coordinate requires mcc_angle_c; // moving speed along co-longitude coordinate requires mcc_angle_c; // moving speed along co-latitude coordinate requires std::same_as; }; // set hardware state: // i.g. 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.hardwareSetState(std::declval()) } -> std::same_as; // get current state { t.hardwareGetState(std::declval()) } -> std::same_as; { t.hardwareStop() } -> std::same_as; // stop any moving { t.hardwareInit() } -> std::same_as; // initialize hardware }; /* MOUNT TELEMETRY DATA CLASS CONCEPT */ template concept mcc_pointing_target_coord_c = mcc_eqt_hrz_coord_c && requires(T t) { requires mcc_angle_c; // ICRS right ascention requires mcc_angle_c; // ICRS declination }; static constexpr void mcc_copy_pointing_target_coord(mcc_pointing_target_coord_c auto const& from_pt, mcc_pointing_target_coord_c auto* to_pt) { if (to_pt == nullptr) { return; } using from_pt_t = std::remove_cvref_t; using to_pt_t = std::remove_cvref_t; if constexpr (std::derived_from && std::copyable) { *to_pt = from_pt; return; } to_pt->pair_kind = from_pt.pair_kind; to_pt->time_point = std::chrono::time_point_casttime_point)::duration>(from_pt.time_point); to_pt->X = (double)from_pt.X; to_pt->Y = (double)from_pt.Y; to_pt->RA_ICRS = (double)from_pt.RA_ICRS; to_pt->DEC_ICRS = (double)from_pt.DEC_ICRS; to_pt->RA_APP = (double)from_pt.RA_APP; to_pt->DEC_APP = (double)from_pt.DEC_APP; to_pt->HA = (double)from_pt.HA; to_pt->AZ = (double)from_pt.AZ; to_pt->ZD = (double)from_pt.ZD; to_pt->ALT = (double)from_pt.ALT; } template concept mcc_telemetry_data_c = mcc_eqt_hrz_coord_c && std::default_initializable && requires(T t) { // target target coordinates requires mcc_pointing_target_coord_c; // 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; // speed along X from hardware encoder requires mcc_angle_c; // speed along Y from hardware encoder // corrections to transform hardware encoder coordinates to apparent celestial ones requires mcc_angle_c; // PCM correction along X-axis requires mcc_angle_c; // PCM correction along Y-axis // atmospheric refraction correction for current zenithal distance requires mcc_angle_c; // for current .ZD }; static constexpr void mcc_copy_telemetry_data(mcc_telemetry_data_c auto const& from_pt, mcc_telemetry_data_c auto* to_pt) { if (to_pt == nullptr) { return; } using from_pt_t = std::remove_cvref_t; using to_pt_t = std::remove_cvref_t; if constexpr (std::derived_from && std::copyable) { *to_pt = from_pt; return; } to_pt->pair_kind = from_pt.pair_kind; to_pt->time_point = std::chrono::time_point_casttime_point)::duration>(from_pt.time_point); to_pt->X = (double)from_pt.X; to_pt->Y = (double)from_pt.Y; to_pt->speedX = (double)from_pt.speedX; to_pt->speedY = (double)from_pt.speedY; to_pt->RA_APP = (double)from_pt.RA_APP; to_pt->DEC_APP = (double)from_pt.DEC_APP; to_pt->HA = (double)from_pt.HA; to_pt->AZ = (double)from_pt.AZ; to_pt->ZD = (double)from_pt.ZD; to_pt->ALT = (double)from_pt.ALT; to_pt->pcmX = (double)from_pt.pcmX; to_pt->pcmY = (double)from_pt.pcmY; to_pt->refCorr = (double)from_pt.refCorr; mcc_copy_pointing_target_coord(from_pt.target, &to_pt->target); } /* MOUNT TELEMETRY MANAGER CLASS CONCEPT */ template struct mcc_telemetry_interface_t { virtual ~mcc_telemetry_interface_t() = default; // update telemetry data right now // an implementation is expected to update the data within the given 'timeout' time interval // if not the method must return an appropriate timeout-error template SelfT> RetT updateTelemetryData(this SelfT&& self, traits::mcc_time_duration_c auto const& timeout) { return std::forward(self).updateTelemetryData(timeout); } // get current data // an implementation is expected to return current, possibly already expired, telemetry data // one should call consistently both 'updateTelemetryData' + 'telemetryData' methods // to ensure that the data is up-to-date template SelfT> RetT telemetryData(this SelfT&& self, mcc_telemetry_data_c auto* data) { return std::forward(self).telemetryData(data); } // waiting for updated data // an implementation is expected to block the current thread waiting for // telemetry data to be updated (internal synchronization) // if a timeout occured the method must return an appropriate timeout-error template SelfT> RetT waitForTelemetryData(this SelfT&& self, mcc_telemetry_data_c auto* data, traits::mcc_time_duration_c auto const& timeout) { return std::forward(self).waitForTelemetryData(data, timeout); } // set target coordinates template SelfT> RetT setPointingTarget(this SelfT&& self, mcc_celestial_point_c auto pt) { return std::forward(self).telemetryData(std::move(pt)); } // compute difference in coordinates: // dx = targetX - mountX // dy = targetY - mountY // where X and Y is in according to 'pair_kind' input parameter template SelfT> RetT targetToMountDiff(this SelfT&& self, MccCoordPairKind pair_kind, mcc_angle_c auto* dx, mcc_angle_c auto* dy) { std::forward(self).targetToMountDiff(pair_kind, dx, dy); } // compute distance between target and actual mount celestial points template SelfT> RetT targetToMountDist(this SelfT&& self, mcc_angle_c auto* dist) { std::forward(self).targetToMountDist(dist); } protected: mcc_telemetry_interface_t() = default; }; template concept mcc_telemetry_c = std::derived_from>; /* PROHIBITED ZONE CLASS CONCEPT */ template struct mcc_pzone_interface_t { virtual ~mcc_pzone_interface_t() = default; template SelfT, typename InputT> RetT inPZone(this SelfT&& self, InputT coords, bool* result) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && requires { self.inPZone(coords, result); } { return std::forward(self).InPZone(std::move(coords), result); } template SelfT, typename InputT> RetT timeToPZone(this SelfT&& self, InputT coords, traits::mcc_time_duration_c auto* res_time) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && requires { self.timeToPZone(coords, res_time); } { return std::forward(self).timeToPZone(std::move(coords), res_time); } template SelfT, typename InputT> RetT timeFromPZone(this SelfT&& self, InputT coords, traits::mcc_time_duration_c auto* res_time) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && requires { self.timeFromPZone(coords, res_time); } { return std::forward(self).timeFromPZone(std::move(coords), res_time); } // // NOTE: the method must return: // point = mcc_celestial_point_c{.pair_kind = MccCoordPairKind::COORDS_KIND_GENERIC, .X = NaN, .Y = NaN} // if there is no intersection with the zone for given coordinates! template SelfT, typename InputT, typename ResultT> RetT intersectPZone(this SelfT&& self, InputT coords, ResultT* point) requires((mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && (mcc_eqt_hrz_coord_c || mcc_celestial_point_c)) && requires { self.intersectPZone(coords, point); } { return std::forward(self).intersectPZone(std::move(coords), point); } // template SelfT, typename InputT> // RetT intersectPZone(this SelfT&& self, InputT coords, mcc_celestial_point_c auto* point) // requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && // requires { self.intersectPZone(coords, point); } // { // return std::forward(self).intersectPZone(std::move(coords), point); // } protected: mcc_pzone_interface_t() = default; }; template concept mcc_prohibited_zone_c = std::derived_from> && requires(const T t_const) { { t_const.name() } -> std::formattable; // the 'T' class must contain static constexpr member of 'MccMountType' type requires std::same_as; []() { static constexpr MccProhibitedZonePolicy val = T::pzPolicy; return val; }(); // to ensure 'pzPolicy' can be used in compile-time context }; /* PROHIBITED ZONES CONTAINER CLASS CONCEPT */ template struct mcc_pzone_container_interface_t { virtual ~mcc_pzone_container_interface_t() = default; template SelfT> size_t addPZone(this SelfT&& self, mcc_prohibited_zone_c auto zone) { return std::forward(self).addPZone(std::move(zone)); } template SelfT> void clearPZones(this SelfT&& self) { return std::forward(self).clearPZones(); } template SelfT> size_t sizePZones(this SelfT&& self) { return std::forward(self).sizePZones(); } template SelfT, typename InputT> RetT inPZone(this SelfT&& self, InputT coords, bool* common_result, std::ranges::output_range auto* result) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) { return std::forward(self).InPZone(std::move(coords), common_result, result); } template SelfT, typename InputT, traits::mcc_time_duration_c DT> RetT timeToPZone(this SelfT&& self, InputT coords, std::ranges::output_range
auto* res_time) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) { return std::forward(self).timeToPZone(std::move(coords), res_time); } template SelfT, typename InputT, traits::mcc_time_duration_c DT> RetT timeFromPZone(this SelfT&& self, InputT coords, std::ranges::output_range
auto* res_time) requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) { return std::forward(self).timeFromPZone(std::move(coords), res_time); } // template SelfT, typename InputT, mcc_celestial_point_c CPT> // RetT intersectPZone(this SelfT&& self, InputT coords, std::ranges::output_range auto* result) // requires(mcc_eqt_hrz_coord_c || mcc_celestial_point_c) // { // return std::forward(self).intersectPZone(std::move(coords), result); // } template SelfT, typename InputT, typename ResultT> RetT intersectPZone(this SelfT&& self, InputT coords, std::ranges::output_range auto* result) requires((mcc_eqt_hrz_coord_c || mcc_celestial_point_c) && (mcc_eqt_hrz_coord_c || mcc_celestial_point_c)) { return std::forward(self).intersectPZone(std::move(coords), result); } protected: mcc_pzone_container_interface_t() = default; }; template concept mcc_pzone_container_c = std::derived_from>; /* MOUNT MOVING MODEL CONCEPT */ template concept mcc_slewing_model_c = requires(T t) { // requires mcc_error_c; // a class of slewing process parameters typename T::slewing_params_t; // requires requires(typename T::slewing_params_t pars) { // // slew mount to target and stop // requires std::convertible_to; // }; // { t.slewToTarget() } -> std::same_as; // { t.stopSlewing() } -> std::same_as; // the method signature: // slewToTarget(bool slew_and_stop) // slew_and_stop == true, slew mount and stop // slew_and_stop == false, slew mount and track { t.slewToTarget(std::declval()) } -> mcc_error_c; { t.stopSlewing() } -> mcc_error_c; { t.setSlewingParams(std::declval()) } -> mcc_error_c; // { t.setSlewingParams(std::declval()) } -> std::same_as; { t.getSlewingParams() } -> std::same_as; }; template concept mcc_tracking_model_c = requires(T t) { // requires mcc_error_c; // a class of tracking process parameters requires requires(typename T::tracking_params_t pars) { requires mcc_angle_c; requires mcc_angle_c; }; // { t.trackTarget() } -> std::same_as; // { t.stopTracking() } -> std::same_as; { t.trackTarget() } -> mcc_error_c; { t.stopTracking() } -> mcc_error_c; { t.setTrackingParams(std::declval()) } -> mcc_error_c; // { t.setTrackingParams(std::declval()) } -> std::same_as; { t.getTrackingParams() } -> std::same_as; }; // template // concept mcc_guiding_model_c = requires(T t) { // requires mcc_error_c; // // a class of guiding process parameters // requires requires(typename T::guiding_params_t pars) { // // guide along both mount axis // requires std::convertible_to; // }; // { t.startGuidingTarget() } -> std::same_as; // { t.stopGuidingTarget() } -> std::same_as; // { t.setGuidingParams(std::declval()) } -> std::same_as; // { t.getGuidingParams() } -> std::same_as; // }; /* GENERIC MOUNT CLASS CONCEPT */ // a concept of class that consist of the full set of coordinate transformation mount control components // (celestial coordinate transformation engine, mount hardware encoders readings and pointing correction model) // the set of methods of this class is enough to transform coordinates from ICRS to hardware and back template concept mcc_position_controls_c = mcc_ccte_c && mcc_hardware_c && mcc_PCM_c; // a class containing full set of mount controls template concept mcc_all_controls_c = mcc_position_controls_c && mcc_telemetry_c && mcc_pzone_container_c; // generic mount: // 1) telemetry-related methods // 2) prohibited zones related methods // 3) slewing and tracking, stop and init mount methods template concept mcc_generic_mount_c = mcc_telemetry_c && mcc_pzone_container_c && requires(T t) { // requires mcc_error_c; // slew mount to target (it is assumed that the target coordinates are determined in the telemetry data) { t.slewToTarget() }; // { t.slewToTarget() } -> std::same_as; // track target, i.e., the mount moves with celestial speed { t.trackTarget() }; // { t.trackTarget() } -> std::same_as; // { t.startGuidingTarget() } -> std::same_as; // { t.stopGuidingTarget() } -> std::same_as; // stop any movement { t.stopMount() }; // { t.stopMount() } -> std::same_as; // init mount { t.initMount() }; }; // with logging methods template concept mcc_generic_log_mount_c = mcc_generic_mount_c && mcc_logger_c; // Finite-state-machine template concept mcc_generic_fsm_mount_c = mcc_generic_mount_c && std::derived_from; template concept mcc_generic_fsm_log_mount_c = mcc_generic_mount_c && mcc_logger_c && std::derived_from; } // namespace mcc