#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* A GENERIC MOUNT CLASS IMPLEMENTATION */ #include #include "mcc_mount_concepts.h" namespace mcc { // adaptor class for prohibited zones template struct MccPZoneWrapper { // a type to which the result of calling prohibited zone class methods 'timeTo' and 'timeFrom' will be converted typedef std::chrono::duration duration_t; // seconds as floating-point number static constexpr duration_t infiniteDuration{std::numeric_limits::infinity()}; static constexpr duration_t zeroDuration{0.0}; typedef std::function pz_inzone_func_t; typedef std::function pz_timeto_func_t; typedef std::function pz_timefrom_func_t; MccCoordPairKind coordPairKind; const std::function name; pz_inzone_func_t inZone; pz_timeto_func_t timeTo; pz_timefrom_func_t timeFrom; }; template class MccGenericMount : public LOGGER_T { typedef LOGGER_T logger_t; using logger_t::logDebug; using logger_t::logError; using logger_t::logInfo; using logger_t::logWarn; typedef ASTROM_ENGINE_T astrom_engine_t; typedef HARDWARE_T hardware_t; typedef PEC_T pec_t; typedef TELEMETRY_T telemetry_t; typedef typename TELEMETRY_T::telemetry_data_t telemetry_data_t; typedef SLEWMODEL_T slew_model_t; typedef GUIDEMODEL_T guiding_model_t; typedef typename MccPZoneWrapper::duration_t pz_duration_t; static constexpr MccMountType mountType = pec_t::mountType; virtual ~MccGenericMount() = default; // get telemetry data auto mountTelemetryData(telemetry_data_t& data) { return _telemetry.data(data); } /* prohibited zone related public methods */ // add zones to mount control system template ZT, traits::mcc_prohibited_zone_c... ZTs> size_t pzAddZone(ZT zone, ZTs... zones) { auto zone_ptr = std::make_shared(std::move(zone)); using d_t = typename MccPZoneWrapper::duration_t; _pzFuncs.emplace_back( {.coordPairKind = ZT::zoneCoordPairKind, .name = [zone_ptr]() { return std::format("{}", zone_ptr->name()); }, .inZone = [zone_ptr](const telemetry_data_t& tmry_data) { return zone_ptr->inZone(tmry_data); }, .timeTo = [zone_ptr](const telemetry_data_t& tmry_data) { auto d = zone_ptr->timeTo(tmry_data); if constexpr (std::same_as) { return d; } else { if (d == ZT::infiniteDuration) { return MccPZoneWrapper::infiniteDuration; } else if (d == ZT::zeroDuration) { return MccPZoneWrapper::zeroDuration; } return std::chrono::duration_cast(d); } }, .timeFrom = [zone_ptr](const telemetry_data_t& tmry_data) { auto d = zone_ptr->timeFrom(tmry_data); if constexpr (std::same_as) { return d; } else { if (d == ZT::infiniteDuration) { return MccPZoneWrapper::infiniteDuration; } else if (d == ZT::zeroDuration) { return MccPZoneWrapper::zeroDuration; } return std::chrono::duration_cast(d); } }}); if constexpr (sizeof...(ZTs)) { pzAddZone(std::move(zones)...); } return _pzFuncs.size(); } // delete all zones from mount control system void pzClearZone() { // stop mount here?!! _pzFuncs.clear(); } // prohibited zones timeTo from given time point template RT, traits::mcc_celestial_point_c CT, traits::mcc_systime_c TPT> RT pzTimeTo(CT coord, const TPT& time_point) requires std::convertible_to { RT res; telemetry_data_t tdata; typename astrom_engine_t::juldate_t jd; _astromEngine.greg2jul(time_point, jd); if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's typename pec_t::pec_result_t pec_res; auto pec_err = _pec.compute(coord.x, coord.y, pec_res); if (!pec_err) { if constexpr (mccIsEquatorialMount(mountType)) { tdata.mntHA = coord.x + pec_res.dx; tdata.mntDEC = coord.y + pec_res.dy; _astromEngine.hadec2azalt(tdata.mntHA, tdata.mntDEC, tdata.mntAZ, tdata.mntALT); } else if constexpr (mccIsAltAzMount(mountType)) { tdata.mntAZ = coord.x + pec_res.dx; tdata.mntALT = coord.y + pec_res.dy; _astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC); } } else { return res; } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC typename astrom_engine_t::eo_t eo; typename astrom_engine_t::sideral_time_t lst; _astromEngine.apparentSiderTime(jd, lst, true); _astromEngine.eqOrigins(jd, eo); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC tdata.mntHA = coord.x; tdata.mntDEC = coord.y; _astromEngine.hadec2azalt(tdata.mntHA, tdata.mntDEC, tdata.mntAZ, tdata.mntALT); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT tdata.mntAZ = coord.x; tdata.mntALT = coord.y; _astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD tdata.mntAZ = coord.x; tdata.mntALT = std::numbers::pi / 2.0 - coord.y; _astromEngine.azalt2hadec(tdata.mntAZ, tdata.mntALT, tdata.mntHA, tdata.mntDEC); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC typename astrom_engine_t::coord_t az, alt; typename astrom_engine_t::eo_t eo; typename astrom_engine_t::juldate_t jd; _astromEngine.greg2jul(time_point, jd); _astromEngine.icrs2obs(coord.x, coord.y, jd, tdata.mntRA, tdata.mntDEC, tdata.mntHA, tdata.mntAZ, tdata.mntALT, eo); } else { return res; } } template auto pzTimeTo(CT point, const TPT& time_point) { return pzTimeTo>(std::move(point), time_point); } // prohibited zones timeTo from current mount position template RT, traits::mcc_celestial_point_c CT> RT pzTimeTo(CT point) { RT result; telemetry_data_t data; auto err = _telemetry.data(data); if (err) { // log... return result; } std::ranges::for_each(_pzFuncs, [&result, &data](auto& funcs) { std::back_inserter(result) = funcs.timeTo(data); }); } template auto pzTimeTo(CT point) { return pzTimeTo>(std::move(point)); } // prohibited zone timeFrom protected: ASTROM_ENGINE_T _astromEngine; HARDWARE_T _hardware; PEC_T _pec; TELEMETRY_T _telemetry; SLEWMODEL_T _slewModel; GUIDEMODEL_T _gudingModel; std::vector> _pzFuncs{}; }; namespace traits { template concept mcc_generic_mount_c = requires(T t) { // derived from MccGenericMount [](MccGenericMount*) {}(&t); { t.slewMount(std::declval()) }; { t.startGuiding(std::declval()) }; { t.stop() }; }; template concept mcc_generic_fsm_mount_c = mcc_generic_mount_c && std::derived_from; } // namespace traits } // namespace mcc