#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* VARIUOS ASTROMETRIC TRANSFORMATIONS FOR TELEMETRY */ #include "mcc_mount_concepts.h" namespace mcc { enum class MccMountTelemetryAstromTransformErrorCode : int { ERROR_OK = 0, ERROR_COORD_PAIR_KIND, ERROR_ASTROMETRY_COMP, ERROR_PEC }; /* error category definition */ // error category struct MccMountTelemetryAstromTransformCategory : public std::error_category { MccMountTelemetryAstromTransformCategory() : std::error_category() {} const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; } std::string message(int ec) const { MccMountTelemetryAstromTransformErrorCode err = static_cast(ec); switch (err) { case MccMountTelemetryAstromTransformErrorCode::ERROR_OK: return "OK"; case MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND: return "unsupported coordinate pair kind"; case MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP: return "astrometry engine error"; case MccMountTelemetryAstromTransformErrorCode::ERROR_PEC: return "PEC computation error"; default: return "UNKNOWN"; } } static const MccMountTelemetryAstromTransformCategory& get() { static const MccMountTelemetryAstromTransformCategory constInst; return constInst; } }; inline std::error_code make_error_code(MccMountTelemetryAstromTransformErrorCode ec) { return std::error_code(static_cast(ec), MccMountTelemetryAstromTransformCategory::get()); } } // namespace mcc namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace mcc { template class MccMountTelemetryAstromTransform { inline static typename ASTROM_ENGINE_T::coord_t dummyCoord{}; public: typedef ASTROM_ENGINE_T astrom_engine_t; typedef PEC_T pec_t; // check for coordinate types consistency static_assert( requires(typename astrom_engine_t::coord_t ac, typename pec_t::coord_t pc) { // to compute PEC-corrected values { ac += pc }; { ac = ac + pc }; { ac = ac - pc }; }, "ASTROMETRY ENGINE AND PEC COORDINATES TYPE MUST BE CONSISTENT!"); // deduce mount type static constexpr bool equatorialMount = mccIsEquatorialMount(PEC_T::mountType); static constexpr bool altAzMount = mccIsAltAzMount(PEC_T::mountType); typedef typename astrom_engine_t::coord_t coord_t; typedef std::error_code error_t; MccMountTelemetryAstromTransform(astrom_engine_t& astrom_engine, pec_t& pec) : _astromEngine(astrom_engine), _pec(pec) { } virtual ~MccMountTelemetryAstromTransform() = default; template error_t toApparent(CT coord, astrom_engine_t::time_point_t time_point, coord_t& X_app, coord_t& Y_app, coord_t& XX_app = dummyCoord) { typedef typename astrom_engine_t::jd_t jd_t; jd_t jd; typedef typename astrom_engine_t::eo_t eo_t; eo_t eo; typedef typename astrom_engine_t::sideral_time_t sideral_time_t; sideral_time_t lst; typename astrom_engine_t::error_t ast_err; typename pec_t::error_t pec_err; auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) { auto ast_err = _astromEngine.greg2jul(time_point, jd); if (!ast_err) { ast_err = _astromEngine.apparentSiderTime(jd, lst, true); if (!ast_err) { ast_err = _astromEngine->eqOrigins(jd, eo); } } return ast_err; }; if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's typename pec_t::pec_result_t pec_res; pec_err = _pec.compute(coord.x, coord.y, pec_res); if (!pec_err) { X_app = coord.x + pec_res.dx; Y_app = coord.y + pec_res.dy; } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC coord_t HA; // logDebug("Input slew coordinates are apparent RA-DEC: convert it to apparent HA-DEC ..."); ast_err = get_jd_lst_eo(jd, lst, eo); if (!ast_err) { HA = lst - coord.x + eo; // HA = LST - RA_APP + EO if constexpr (equatorialMount) { // compute HA (as XX_app) X_app = coord.x; Y_app = coord.y; XX_app = HA; } else if constexpr (altAzMount) { ast_err = _astromEngine.hadec2azalt(HA, coord.y, X_app, Y_app); } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC ast_err = get_jd_lst_eo(jd, lst, eo); if (!ast_err) { if constexpr (equatorialMount) { // compute CIO RA (as XX_app) X_app = coord.x; Y_app = coord.y; XX_app = lst - coord.x + eo; } else if constexpr (altAzMount) { ast_err = _astromEngine.hadec2azalt(coord.x, coord.y, X_app, Y_app); } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT if constexpr (equatorialMount) { ast_err = azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC if (!ast_err) { // compute CIO RA (as XX_app) ast_err = toApparent(X_app, Y_app, X_app, Y_app, XX_app); } } else if (altAzMount) { X_app = coord.x; Y_app = coord.y; } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT; coord.y = std::numbers::pi / 2.0 - coord.y; ast_err = toApparent(std::move(coord), std::move(time_point), X_app, Y_app, XX_app); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC coord_t az, alt; eo_t eo; // for equatorial mount: // X_app = RA_app, Y_app = DEC_app, XX_app = HA_app // for alt-azimuthal mount: // X_app = AZ, Y_app = ALT ast_err = _astromEngine.greg2jul(time_point, jd); if (!ast_err) { ast_err = _astromEngine.icrs2obs(coord.x, coord.y, jd, X_app, Y_app, XX_app, az, alt, eo); if (!ast_err) { if constexpr (equatorialMount) { // nothing to do } else if (altAzMount) { X_app = az; Y_app = alt; } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } } } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND; } if (pec_err) { if constexpr (std::same_as) { return pec_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC; } } if (ast_err) { if constexpr (std::same_as) { return ast_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP; } } return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } template error_t toICRS(CT coord, astrom_engine_t::time_point_t time_point, coord_t& RA, coord_t& DEC) { typename astrom_engine_t::error_t ast_err; typename pec_t::error_t pec_err; if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's typename pec_t::pec_result_t pec_res; pec_err = _pec.compute(coord.x, coord.y, pec_res); if (!pec_err) { coord.x += pec_res.dx; coord.y += pec_res.dy; if constexpr (equatorialMount) { coord.coordPairKind = MccCoordPairKind::COORDS_KIND_HADEC_APP; } else if constexpr (altAzMount) { coord.coordPairKind = MccCoordPairKind::COORDS_KIND_AZALT; } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } ast_err = toICRS(std::move(coord), std::move(time_point), RA, DEC); } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT; coord.y = std::numbers::pi / 2.0 - coord.y; ast_err = toICRS(std::move(coord), std::move(time_point), RA, DEC); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC RA = coord.x; DEC = coord.y; return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND; } if (coord.coordPairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { typename astrom_engine_t::jd_t jd; ast_err = _astromEngine.greg2jul(astrom_engine_t::timePointNow(), jd); if (!ast_err) { ast_err = _astromEngine.obs2icrs(coord.coordPairKind, coord.x, coord.y, jd, RA, DEC); } } if (pec_err) { if constexpr (std::same_as) { return pec_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC; } } if (ast_err) { if constexpr (std::same_as) { return ast_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP; } } return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } template error_t toHardware(CT coord, astrom_engine_t::time_point_t time_point, coord_t& X, coord_t& Y) { typedef typename astrom_engine_t::jd_t jd_t; jd_t jd; typedef typename astrom_engine_t::eo_t eo_t; eo_t eo; typedef typename astrom_engine_t::sideral_time_t sideral_time_t; sideral_time_t lst; auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) { auto ast_err = _astromEngine.greg2jul(time_point, jd); if (!ast_err) { ast_err = _astromEngine.apparentSiderTime(jd, lst, true); if (!ast_err) { ast_err = _astromEngine->eqOrigins(jd, eo); } } return ast_err; }; typename astrom_engine_t::error_t ast_err; typename pec_t::error_t pec_err; if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's X = coord.x; Y = coord.y; return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { // from app RA-DEC ast_err = get_jd_lst_eo(jd, lst, eo); if (!ast_err) { coord.x = lst - coord.x + eo; // HA coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP; ast_err = toHardware(std::move(coord), std::move(time_point), X, Y); } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP) { // from app HA-DEC if constexpr (equatorialMount) { typename pec_t::pec_result_t pec_res; pec_err = _pec.compute(coord.x, coord.y, pec_res); if (!pec_err) { X = coord.x - pec_res.dx; Y = coord.y - pec_res.dy; return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } } else if constexpr (altAzMount) { coord_t az, alt; ast_err = _astromEngine.hadec2azalt(coord.x, coord.y, az, alt); if (!ast_err) { coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT; coord.x = az; coord.y = alt; ast_err = toHardware(std::move(coord), std::move(time_point), X, Y); } } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT if constexpr (equatorialMount) { coord_t ha, dec; ast_err = _astromEngine.azalt2hadec(coord.x, coord.y, ha, dec); if (!ast_err) { coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP; coord.x = ha; coord.y = dec; ast_err = toHardware(std::move(coord), std::move(time_point), X, Y); } } else if constexpr (altAzMount) { typename pec_t::pec_result_t pec_res; pec_err = _pec.compute(coord.x, coord.y, pec_res); if (!pec_err) { X = coord.x - pec_res.dx; Y = coord.y - pec_res.dy; return {}; } } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZZD) { // from app AZ-ZD coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT; coord.y = std::numbers::pi / 2.0 - coord.y; ast_err = toICRS(std::move(coord), std::move(time_point), X, Y); } else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS RA-DEC coord_t ra, dec, ha, az, alt; eo_t eo; ast_err = _astromEngine.greg2jul(time_point, jd); if (!ast_err) { ast_err = icrs2obs(coord.x, coord.y, jd, ra, dec, ha, az, alt, eo); if (!ast_err) { if constexpr (equatorialMount) { coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP; coord.x = ha; coord.y = dec; } else if constexpr (altAzMount) { coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT; coord.x = az; coord.y = alt; } else { static_assert(false, "UNSUPPORTED MOUNT TYPE!"); } ast_err = toHardware(std::move(coord), std::move(time_point), X, Y); } } } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_COORD_PAIR_KIND; } if (pec_err) { if constexpr (std::same_as) { return pec_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_PEC; } } if (ast_err) { if constexpr (std::same_as) { return ast_err; } else { return MccMountTelemetryAstromTransformErrorCode::ERROR_ASTROMETRY_COMP; } } return MccMountTelemetryAstromTransformErrorCode::ERROR_OK; } protected: astrom_engine_t& _astromEngine; pec_t& _pec; }; } // namespace mcc