diff --git a/mcc/CMakeLists.txt b/mcc/CMakeLists.txt index bd6ecbb..c74fe68 100644 --- a/mcc/CMakeLists.txt +++ b/mcc/CMakeLists.txt @@ -85,7 +85,7 @@ if (WITH_TESTS) set(CTTE_TEST_APP ccte_test) add_executable(${CTTE_TEST_APP} tests/ccte_test.cpp) target_include_directories(${CTTE_TEST_APP} PRIVATE ${ERFA_INCLUDE_DIR}) - target_link_libraries(${CTTE_TEST_APP} ERFA_LIB) + target_link_libraries(${CTTE_TEST_APP} ERFA_LIB bsplines) enable_testing() endif() diff --git a/mcc/mcc_ccte_erfa.h b/mcc/mcc_ccte_erfa.h index 8ab9696..7c9d99c 100644 --- a/mcc/mcc_ccte_erfa.h +++ b/mcc/mcc_ccte_erfa.h @@ -399,7 +399,7 @@ public: { error_t ret = MccCCTE_ERFAErrorCode::ERROR_OK; - MccJulianDay jd; + // MccJulianDay jd; if (to_pt == nullptr) { return ret; @@ -476,7 +476,8 @@ public: return transformCoordinates(pt, to_pt); } } else { // the same time points - double eo, lst, ha, dec, az, alt; + double eo, lst, ha; + // , dec, az, alt; auto lst_eo = [&]() { // ret = eqOrigins(from_pt.time_point, &eo); @@ -517,7 +518,7 @@ public: } else if (to_pt->pair_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) { lst_eo(); if (!ret) { - to_pt->X = lst - from_pt.X + eo; + to_pt->X = MccAngle(lst - from_pt.X + eo).normalize(); to_pt->Y = from_pt.Y; } else { return ret; @@ -541,7 +542,7 @@ public: azalt2hadec(from_pt, to_pt); lst_eo(); if (!ret) { - to_pt->X = lst - to_pt->X + eo; + to_pt->X = MccAngle(lst - to_pt->X + eo).normalize(); } } else { ret = MccCCTE_ERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR; @@ -560,7 +561,7 @@ public: { error_t ret = MccCCTE_ERFAErrorCode::ERROR_OK; - MccJulianDay jd; + // MccJulianDay jd; if (to_pt == nullptr) { return ret; diff --git a/mcc/mcc_defaults.h b/mcc/mcc_defaults.h index 74428ac..2ddbb5e 100644 --- a/mcc/mcc_defaults.h +++ b/mcc/mcc_defaults.h @@ -104,6 +104,16 @@ struct MccGenericPointingTarget : MccGenericEqtHrzCoords { typedef MccGenericPointingTarget MccPointingTarget; + +template +struct MccGenericPCMResult { + CoordT pcmX, pcmY; +}; + + +typedef MccGenericPCMResult MccPCMResult; + + /* DEFAULT TELEMETRY DATA CLASS */ template diff --git a/mcc/mcc_generics.h b/mcc/mcc_generics.h index 346c280..36fba12 100644 --- a/mcc/mcc_generics.h +++ b/mcc/mcc_generics.h @@ -136,6 +136,13 @@ 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 @@ -327,18 +334,66 @@ concept mcc_ccte_c = std::derived_from concept mcc_PCM_result_c = requires(T t) { - requires mcc_angle_c; - requires mcc_angle_c; + requires mcc_angle_c; + requires mcc_angle_c; }; -template +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, ResT* result) + 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); + 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: @@ -346,15 +401,14 @@ protected: }; 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 - }; +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 +}; @@ -404,13 +458,13 @@ concept mcc_hardware_c = requires(T t, const T t_const) { - // a class that contains at least time point of measurement, coordinates for x,y axes, its moving rates and moving - // type - requires requires(typename T::hardware_state_t state) { - requires mcc_time_point_c; // time point + // 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; // 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 diff --git a/mcc/mcc_pcm.h b/mcc/mcc_pcm.h index f75b811..a1621f1 100644 --- a/mcc/mcc_pcm.h +++ b/mcc/mcc_pcm.h @@ -73,16 +73,6 @@ class is_error_code_enum : public true_type namespace mcc { -namespace details -{ - -template -struct _pcm_result_t { - CT dx, dy; -}; - - -} // namespace details // type of PCM corrections (algorithm used): // PCM_TYPE_GEOMETRY - "classic" geometry-based correction coefficients @@ -91,7 +81,7 @@ struct _pcm_result_t { enum class MccDefaultPCMType { PCM_TYPE_GEOMETRY, PCM_TYPE_GEOMETRY_BSPLINE, PCM_TYPE_BSPLINE }; template -class MccDefaultPCM : public mcc_PCM_interface_t> +class MccDefaultPCM : public mcc_PCM_interface_t { public: static constexpr MccMountType mountType = MOUNT_TYPE; @@ -99,7 +89,6 @@ public: typedef std::error_code error_t; typedef double coord_t; - typedef details::_pcm_result_t pcm_result_t; // "classic" geometric PEC coefficients struct pcm_geom_coeffs_t { @@ -143,7 +132,11 @@ public: // constructors - MccDefaultPCM(pcm_data_t pdata) : _pecData(std::move(pdata)), _pecDataMutex(new std::mutex) {} + MccDefaultPCM() : _pcmDataMutex(new std::mutex) {} + MccDefaultPCM(pcm_data_t pdata) : MccDefaultPCM() + { + _pcmData = std::move(pdata); + } MccDefaultPCM(MccDefaultPCM&& other) = default; MccDefaultPCM& operator=(MccDefaultPCM&& other) = default; @@ -153,47 +146,49 @@ public: virtual ~MccDefaultPCM() = default; - void setData(pcm_data_t pdata) + void setPCMData(pcm_data_t pdata) { - std::lock_guard lock(*_pecDataMutex); + std::lock_guard lock(*_pcmDataMutex); - _pecData = std::move(pdata); + _pcmData = std::move(pdata); } - pcm_data_t getData() const + pcm_data_t getPCMData() const { - std::lock_guard lock(*_pecDataMutex); + std::lock_guard lock(*_pcmDataMutex); - return _pecData; + return _pcmData; } - void setType(MccDefaultPCMType type) + void setPCMType(MccDefaultPCMType type) { - std::lock_guard lock(*_pecDataMutex); + std::lock_guard lock(*_pcmDataMutex); - _pecData.type = type; + _pcmData.type = type; } - MccDefaultPCMType getType() const + MccDefaultPCMType getPCMType() const { - std::lock_guard lock(*_pecDataMutex); + std::lock_guard lock(*_pcmDataMutex); - return _pecData.type; + return _pcmData.type; } - // The computed PEC quantities must be interpretated as: - // apparent_X = encoder_X + pcm_result_t.dx - // apparent_Y = encoder_Y + pcm_result_t.dy + // The computed PCM quantities must be interpretated as: + // apparent_X = encoder_X + res.pcmX + // apparent_Y = encoder_Y + res.pcmY // so, input x and y are assumed to be mount axis encoder coordinates - error_t compute(mcc_celestial_point_c auto pt, pcm_result_t& res) + template + error_t computePCM(mcc_celestial_point_c auto pt, mcc_PCM_c auto* res, T* app_pt = nullptr) + requires(mcc_celestial_point_c || mcc_eqt_hrz_coord_c || std::same_as) { - std::lock_guard lock(*_pecDataMutex); + std::lock_guard lock(*_pcmDataMutex); if constexpr (mcc_is_equatorial_mount) { // equatorial - if (_pecData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY) { - const auto cosPhi = std::cos(_pecData.siteLatitude); - const auto sinPhi = std::sin(_pecData.siteLatitude); + if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY) { + const auto cosPhi = std::cos(_pcmData.siteLatitude); + const auto sinPhi = std::sin(_pcmData.siteLatitude); const auto tanY = std::tan(pt.Y); const auto sinX = std::sin(pt.X); const auto cosX = std::cos(pt.X); @@ -201,55 +196,55 @@ public: if (utils::isEqual(cosY, 0.0)) { - res.dx = _pecData.geomCoefficients.zeroPointX; + res->pcmX = _pcmData.geomCoefficients.zeroPointX; } else { - res.dx = _pecData.geomCoefficients.zeroPointX + _pecData.geomCoefficients.collimationErr / cosY + - _pecData.geomCoefficients.nonperpendErr * tanY - - _pecData.geomCoefficients.misalignErr1 * cosX * tanY + - _pecData.geomCoefficients.misalignErr2 * sinX * tanY + - _pecData.geomCoefficients.tubeFlexure * cosPhi * sinX / cosY - - _pecData.geomCoefficients.DECaxisFlexure * (cosPhi * cosX + sinPhi * tanY); + res->pcmX = _pcmData.geomCoefficients.zeroPointX + _pcmData.geomCoefficients.collimationErr / cosY + + _pcmData.geomCoefficients.nonperpendErr * tanY - + _pcmData.geomCoefficients.misalignErr1 * cosX * tanY + + _pcmData.geomCoefficients.misalignErr2 * sinX * tanY + + _pcmData.geomCoefficients.tubeFlexure * cosPhi * sinX / cosY - + _pcmData.geomCoefficients.DECaxisFlexure * (cosPhi * cosX + sinPhi * tanY); } - res.dy = _pecData.geomCoefficients.zeroPointY + _pecData.geomCoefficients.misalignErr1 * sinX + - _pecData.geomCoefficients.misalignErr2 * cosX + - _pecData.geomCoefficients.tubeFlexure * (cosPhi * cosX * std::sin(pt.Y) - sinPhi * cosY); + res->pcmY = _pcmData.geomCoefficients.zeroPointY + _pcmData.geomCoefficients.misalignErr1 * sinX + + _pcmData.geomCoefficients.misalignErr2 * cosX + + _pcmData.geomCoefficients.tubeFlexure * (cosPhi * cosX * std::sin(pt.Y) - sinPhi * cosY); if constexpr (mountType == MccMountType::FORK_TYPE) { if (!utils::isEqual(cosX, 0.0)) { - res.dy += _pecData.geomCoefficients.forkFlexure / cosX; + res->pcmY += _pcmData.geomCoefficients.forkFlexure / cosX; } } } - if (_pecData.type == MccDefaultPCMType::PCM_TYPE_BSPLINE || - _pecData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) { + if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_BSPLINE || + _pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) { double spl_valX, spl_valY; - int ret = bsplines::fitpack_eval_spl2d(_pecData.bspline.knotsX, _pecData.bspline.knotsY, - _pecData.bspline.coeffsX, pt.X, pt.Y, spl_valX, - _pecData.bspline.bsplDegreeX, _pecData.bspline.bsplDegreeY); + int ret = bsplines::fitpack_eval_spl2d(_pcmData.bspline.knotsX, _pcmData.bspline.knotsY, + _pcmData.bspline.coeffsX, pt.X, pt.Y, spl_valX, + _pcmData.bspline.bsplDegreeX, _pcmData.bspline.bsplDegreeY); if (ret) { - res.dx = std::numeric_limits::quiet_NaN(); - res.dy = std::numeric_limits::quiet_NaN(); + res->pcmX = std::numeric_limits::quiet_NaN(); + res->pcmY = std::numeric_limits::quiet_NaN(); return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV; } - ret = bsplines::fitpack_eval_spl2d(_pecData.bspline.knotsX, _pecData.bspline.knotsY, - _pecData.bspline.coeffsY, pt.X, pt.Y, spl_valY, - _pecData.bspline.bsplDegreeX, _pecData.bspline.bsplDegreeY); + ret = bsplines::fitpack_eval_spl2d(_pcmData.bspline.knotsX, _pcmData.bspline.knotsY, + _pcmData.bspline.coeffsY, pt.X, pt.Y, spl_valY, + _pcmData.bspline.bsplDegreeX, _pcmData.bspline.bsplDegreeY); if (ret) { - res.dx = std::numeric_limits::quiet_NaN(); - res.dy = std::numeric_limits::quiet_NaN(); + res->pcmX = std::numeric_limits::quiet_NaN(); + res->pcmY = std::numeric_limits::quiet_NaN(); return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV; } - res.dx += spl_valX; - res.dy += spl_valY; + res->pcmX += spl_valX; + res->pcmY += spl_valY; } } else if constexpr (mcc_is_altaz_mount) { static_assert(false, "NOT IMPLEMENTED!"); @@ -257,14 +252,65 @@ public: static_assert(false, "UNSUPPORTED"); } + if constexpr (!std::is_null_pointer_v) { + if constexpr (mcc_eqt_hrz_coord_c) { + if constexpr (mccIsEquatorialMount(mountType)) { + app_pt->HA = pt.X + res->pcmX; + app_pt->DEC_APP = pt.Y + res->pcmY; + } else if constexpr (mccIsAltAzMount(mountType)) { + app_pt->AZ = pt.X + res->pcmX; + app_pt->ZD = pt.Y + res->pcmY; + } else { + static_assert(false, "UNKNOW MOUNT TYPE!"); + } + } else { + app_pt->X = pt.X + res->pcmX; + app_pt->Y = pt.Y + res->pcmY; + } + } + + return MccDefaultPCMErrorCode::ERROR_OK; } + template + error_t computeInversePCM(T app_pt, mcc_PCM_result_c auto* result, mcc_celestial_point_c auto* hw_pt = nullptr) + requires(mcc_celestial_point_c || mcc_eqt_hrz_coord_c) + { + // for small corrections only!!! + auto ret = computePCM(std::move(app_pt), result); + if (ret) { + return ret; + } + + result->pcmX = -result->pcmX; + result->pcmY = -result->pcmY; + + if (hw_pt != nullptr) { + if constexpr (mcc_eqt_hrz_coord_c) { + if constexpr (mccIsEquatorialMount(mountType)) { + hw_pt->X = app_pt.HA + result->pcmX; + hw_pt->Y = app_pt.DEC_APP + result->pcmY; + } else if constexpr (mccIsAltAzMount(mountType)) { + hw_pt->X = app_pt.AZ + result->pcmX; + hw_pt->Y = app_pt.ZD + result->pcmY; + } else { + static_assert(false, "UNKNOW MOUNT TYPE!"); + } + } else { + hw_pt->X = app_pt.X + result->pcmX; + hw_pt->Y = app_pt.Y + result->pcmY; + } + } + + + return ret; + } private: - pcm_data_t _pecData; + pcm_data_t _pcmData; - std::unique_ptr _pecDataMutex; + std::unique_ptr _pcmDataMutex; }; diff --git a/mcc/mcc_pzone.h b/mcc/mcc_pzone.h index 0359d89..91ed33c 100644 --- a/mcc/mcc_pzone.h +++ b/mcc/mcc_pzone.h @@ -294,8 +294,9 @@ public: ha = coords.HA; dec = coords.DEC_APP; } else { - MccCelestialPoint to_pt{.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP, - .time_point = coords.time_point}; + MccCelestialPoint to_pt{.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP}; + mcc_tp2tp(coords.time_point, to_pt.time_point); + ret = getCoord(coords, &to_pt); if (ret) { return ret; @@ -310,7 +311,7 @@ public: auto cos_ha = (_sinAlim - sinDec * _sinLat) / cosDec / _cosLat; if (cos_ha > 1.0) { // no intersection - point->pair_kind = MccCoordPairKind::COORDS_KIND_GENERIC; + // point->pair_kind = MccCoordPairKind::COORDS_KIND_GENERIC; point->X = std::numeric_limits::quiet_NaN(); point->Y = std::numeric_limits::quiet_NaN(); @@ -328,14 +329,16 @@ public: az = -std::acos(cosA); } - MccCelestialPoint pt{ - .pair_kind = MccCoordPairKind::COORDS_KIND_AZALT, .time_point = coords.time_point, .X = az, .Y = _altLimit}, - to_pt{.pair_kind = point->pair_kind, .time_point = point->time_point}; + MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT, .X = az, .Y = _altLimit}; + mcc_tp2tp(coords.time_point, pt.time_point); + + MccCelestialPoint to_pt{.pair_kind = point->pair_kind}; + mcc_tp2tp(point->time_point, to_pt.time_point); ret = _transformCoordinates(pt, &to_pt); if (!ret) { - point->X = to_pt.X; - point->Y = to_pt.Y; + point->X = MccAngle(to_pt.X).normalize(); + point->Y = MccAngle(to_pt.Y).normalize(); } return ret; diff --git a/mcc/mcc_pzone_container.h b/mcc/mcc_pzone_container.h index 08b780a..d2ab2b9 100644 --- a/mcc/mcc_pzone_container.h +++ b/mcc/mcc_pzone_container.h @@ -320,14 +320,18 @@ public: MccCelestialPoint pt; auto apply_func = [&](auto& func, auto& pt_arg, size_t i) { + auto ptr = result->begin(); + std::ranges::advance(ptr, i); + + pt.pair_kind = ptr->pair_kind; + pt.time_point = ptr->time_point; + error_t ret = func(pt_arg, &pt); if (!ret) { // if (traits::mcc_range_size(*result) == i) { // std::back_inserter(*result) = CPT(); // } - auto ptr = result->begin(); - std::ranges::advance(ptr, i); mcc_copy_celestial_point(pt, &(*ptr)); } diff --git a/mcc/mcc_telemetry.h b/mcc/mcc_telemetry.h index 9af226c..e94cba6 100644 --- a/mcc/mcc_telemetry.h +++ b/mcc/mcc_telemetry.h @@ -191,41 +191,39 @@ public: } - // compute hardware coordinates - // WARNING: It is assumed here that PCM corrections have small (arcseconds-arcminutes) values - // since ususaly there is no reverse transformation for "hardware-to-apparent" relation! typename pcm_t::error_t pcm_err; - struct { - double dx, dy; - } pcm_res; + MccPCMResult pcm_res; + // MccCelestialPoint pt; + // pt.time_point = + // std::chrono::time_point_cast(_data.target.time_point); - MccCelestialPoint pt; - pt.time_point = - std::chrono::time_point_cast(_data.target.time_point); + pcm_err = pcm->computeInversePCM(_data, &pcm_res, &_data); - if constexpr (mccIsEquatorialMount(pcm_t::mountType)) { - pt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP; - pt.X = _data.target.HA; - pt.Y = _data.target.DEC_APP; - pcm_err = pcm->compute(std::move(pt), &pcm_res); - if (!pcm_err) { - _data.target.X = _data.target.HA - pcm_res.dx; - _data.target.Y = _data.target.DEC_APP - pcm_res.dy; - } - } else if constexpr (mccIsAltAzMount(pcm_t::mountType)) { - pt.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT; - pt.X = _data.target.AZ; - pt.Y = _data.target.ALT; - pcm_err = pcm->compute(std::move(pt), &pcm_res); - if (!pcm_err) { - _data.target.X = _data.target.AZ - pcm_res.dx; - _data.target.Y = _data.target.ALT - pcm_res.dy; - } - } else { - static_assert(false, "UNKNOWN MOUNT TYPE!"); - } + // if constexpr (mccIsEquatorialMount(pcm_t::mountType)) { + // pcm_err = pcm->computeInversePCM(_data, &pcm_res, &_data); + + // pt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP; + // pt.X = _data.target.HA; + // pt.Y = _data.target.DEC_APP; + // pcm_err = pcm->computeInversePCM(std::move(pt), &pcm_res); + // if (!pcm_err) { + // _data.target.X = _data.target.HA - pcm_res.pcmX; + // _data.target.Y = _data.target.DEC_APP - pcm_res.pcmY; + // } + // } else if constexpr (mccIsAltAzMount(pcm_t::mountType)) { + // pt.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT; + // pt.X = _data.target.AZ; + // pt.Y = _data.target.ALT; + // pcm_err = pcm->computeInversePCM(std::move(pt), &pcm_res); + // if (!pcm_err) { + // _data.target.X = _data.target.AZ - pcm_res.pcmX; + // _data.target.Y = _data.target.ALT - pcm_res.pcmY; + // } + // } else { + // static_assert(false, "UNKNOWN MOUNT TYPE!"); + // } if (pcm_err) { return mcc_deduce_error(pcm_err, MccTelemetryErrorCode::ERROR_PCM_COMP); @@ -281,18 +279,12 @@ public: _data.speedX = (double)hw_pos.speedX; _data.speedY = (double)hw_pos.speedY; - struct { - double dx, dy; - } pcm_res; - - auto pcm_err = pcm->computePCM(_data, &pcm_res); + // fill _data.pcmX, _data.pcmY and corresponded apparent coordinates + auto pcm_err = pcm->computePCM(_data, &_data, &_data); if (pcm_err) { return mcc_deduce_error(pcm_err, MccTelemetryErrorCode::ERROR_PCM_COMP); } - _data.pcmX = pcm_res.dx; - _data.pcmY = pcm_res.dy; - if (stop_token.stop_requested()) { return MccTelemetryErrorCode::ERROR_UPDATE_STOPPED; } @@ -300,8 +292,6 @@ public: MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT, .time_point = _data.time_point}; if constexpr (mccIsEquatorialMount(pcm_t::mountType)) { - _data.HA = (double)hw_pos.X + pcm_res.dx; - _data.DEC_APP = (double)hw_pos.Y + pcm_res.dy; _data.RA_APP = (double)_data.LST - (double)_data.HA + eo; _data.X = _data.HA; @@ -316,14 +306,12 @@ public: _data.ZD = std::numbers::pi / 2.0 - _data.ALT; } } else if constexpr (mccIsAltAzMount(pcm_t::mountType)) { - _data.AZ = (double)hw_pos.X + pcm_res.dx; - _data.ALT = (double)hw_pos.Y + pcm_res.dy; - _data.ZD = std::numbers::pi / 2.0 - _data.ALT; + _data.ALT = std::numbers::pi / 2.0 - _data.ZD; _data.X = _data.AZ; - _data.Y = _data.ALT; + _data.Y = _data.ZD; - _data.pair_kind = MccCoordPairKind::COORDS_KIND_AZALT; + _data.pair_kind = MccCoordPairKind::COORDS_KIND_AZZD; pt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP; ccte_err = ccte->transformCoordinates(_data, &pt); diff --git a/mcc/mcc_tracking_model.h b/mcc/mcc_tracking_model.h index f04bfa6..a8fc036 100644 --- a/mcc/mcc_tracking_model.h +++ b/mcc/mcc_tracking_model.h @@ -18,7 +18,7 @@ enum class MccSimpleTrackingModelErrorCode : int { ERROR_HW_GETSTATE, ERROR_HW_SETSTATE, ERROR_PCM_COMP, - ERROR_TELEMETRY_TIMEOUT, + ERROR_GET_TELEMETRY, ERROR_PZONE_CONTAINER_COMP, ERROR_IN_PZONE, ERROR_NEAR_PZONE, @@ -80,11 +80,9 @@ public: // compute position in future auto err = hardware->hardwareGetState(&hw_state); if (err) { - return mcc_deduce_error(err, MccSimpleTrackingModelErrorCode::ERROR_HW_GETSTATE); + return mcc_deduce_error(err, MccSimpleTrackingModelErrorCode::ERROR_HW_GETSTATE); } - cpt.time_point = std::chrono::time_point_cast(hw_state.time_point); - if constexpr (mccIsEquatorialMount(PcmT::mountType)) { cpt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP; } else if constexpr (mccIsAltAzMount(PcmT::mountType)) { @@ -94,62 +92,94 @@ public: static_assert(false, "UNKNOW MOUNT TYPE!"); } - cpt.X = hw_state.X; - cpt.Y = hw_state.Y; - struct { - double dx, dy; - } pcm_res; - - auto pcm_err = pcm->computePCM(cpt, &pcm_res); - if (pcm_err) { - return mcc_deduce_error(pcm_err, MccSimpleTrackingModelErrorCode::ERROR_PCM_COMP); + MccTelemetryData tdata; + auto t_err = telemetry->waitForTelemetryData(&tdata, _currentTrackParams.telemetryTimeout); + if (t_err) { + return mcc_deduce_error(t_err, MccSimpleTrackingModelErrorCode::ERROR_GET_TELEMETRY); } - // to celestial coordinates - cpt.X += pcm_res.dx; - cpt.Y += pcm_res.dy; + mcc_tp2tp(tdata.time_point, cpt.time_point); + std::vector> pz_timeto; // in seconds + std::chrono::duration min_time{0.0}; + std::vector intsc_pt(pz_cont->sizePZones(), cpt); + + // compute intersection points with the prohibited zones + auto pz_err = pz_cont->intersectPZone(tdata, &intsc_pt); + if (pz_err) { + return mcc_deduce_error(pz_err, MccSimpleTrackingModelErrorCode::ERROR_PZONE_CONTAINER_COMP); + } + if constexpr (mccIsEquatorialMount(PcmT::mountType)) { - cpt.pair_kind = MccCoordPairKind::COORDS_KIND_HADEC_APP; + double dha_min = 0.0, dha; + // find the closest pzone + for (auto& ipt : intsc_pt) { + if (std::isfinite(ipt.X) && std::isfinite(ipt.Y)) { + dha = ipt.X - tdata.HA; + if (dha < 0.0) { + dha += std::numbers::pi * 2.0; + } + + if (dha < dha_min) { + dha_min = dha; + cpt.X = ipt.X; + cpt.Y = ipt.Y; + } + } + } + + if (utils::isEqual(dha_min, 0.0)) { // no intersections + cpt.X = tdata.HA - 1.0_mins; + cpt.Y = tdata.DEC_APP; + } + + MccPCMResult pcm_inv_res; + + // endpoint of the mount moving + auto pcm_err = pcm->computeInversePCM(cpt, &pcm_inv_res, &hw_state); + if (pcm_err) { + return mcc_deduce_error(pcm_err, MccSimpleTrackingModelErrorCode::ERROR_PCM_COMP); + } // just set sideral rate once - // hw_state.time_point; + mcc_tp2tp(cpt.time_point, hw_state.time_point); hw_state.speedX = _currentTrackParams.trackSpeedX; hw_state.speedY = _currentTrackParams.trackSpeedY; hw_state.moving_type = HardwareT::hardware_moving_state_t::HW_MOVE_TRACKING; + // start tracking err = hardware->hardwareSetState(std::move(hw_state)); if (err) { - return mcc_deduce_error(err, MccSimpleTrackingModelErrorCode::ERROR_HW_SETSTATE); + return mcc_deduce_error(err, MccSimpleTrackingModelErrorCode::ERROR_HW_SETSTATE); } - // control prohibited zones - MccTelemetryData tdata; - std::vector> pz_timeto; // in seconds - - // std::vector pz_flags; - // bool inzone_flag; while (!*_stopTracking) { - auto pz_err = pz_cont->timeToPZone(tdata, &pz_timeto); + // control prohibited zones + pz_err = pz_cont->timeToPZone(tdata, &pz_timeto); if (pz_err) { - return mcc_deduce_error(pz_err, MccSimpleTrackingModelErrorCode::ERROR_PZONE_CONTAINER_COMP); + return mcc_deduce_error(pz_err, + MccSimpleTrackingModelErrorCode::ERROR_PZONE_CONTAINER_COMP); } + min_time = std::chrono::duration{0}; for (size_t i = 0; i < pz_cont->sizePZones(); ++i) { if (pz_timeto[i] <= _currentTrackParams.minTimeToPZone) { return MccSimpleTrackingModelErrorCode::ERROR_NEAR_PZONE; } + if (pz_timeto[i] < min_time) { + min_time = pz_timeto[i]; + } } - auto t_err = telemetry->waitForTelemetryData(&tdata, _currentTrackParams.telemetryTimeout); + t_err = telemetry->waitForTelemetryData(&tdata, _currentTrackParams.telemetryTimeout); if (t_err) { - return mcc_deduce_error(t_err, MccSimpleTrackingModelErrorCode::ERROR_TELEMETRY_TIMEOUT); + return mcc_deduce_error(t_err, MccSimpleTrackingModelErrorCode::ERROR_GET_TELEMETRY); } if (*_stopTracking) { @@ -161,16 +191,6 @@ public: // unhandled stop state?!!! return MccSimpleTrackingModelErrorCode::ERROR_UNEXPECTED_AXIS_RATES; } - - // auto pz_err = mount->inPZone(tdata, &inzone_flag, &pz_flags); - // if (pz_err) { - // return mcc_deduce_error(t_err, MccSimpleTrackingModelErrorCode::ERROR_PZONE_CONTAINER_COMP); - // } - - // if (inzone_flag) { - // // logging - // return MccSimpleTrackingModelErrorCode::ERROR_IN_PZONE; - // } } return MccSimpleTrackingModelErrorCode::ERROR_OK; diff --git a/mcc/mcc_utils.h b/mcc/mcc_utils.h index e112824..532fb57 100644 --- a/mcc/mcc_utils.h +++ b/mcc/mcc_utils.h @@ -223,6 +223,11 @@ static R rad2sxg(double ang, bool hms = false, int prec = 2) { R res; + if (!std::isfinite(ang)) { + std::vformat_to(std::back_inserter(res), "{}", std::make_format_args(ang)); + return res; + } + std::string fmt = "{:02.0f}:{:02.0f}:{:0" + std::to_string(prec + 3) + "." + std::to_string(prec) + "f}"; // std::string fmt = "{:02.0f}:{:02.0f}:{:02." + std::to_string(prec) + "f}"; diff --git a/mcc/tests/ccte_test.cpp b/mcc/tests/ccte_test.cpp index d05d522..c7e2e5e 100644 --- a/mcc/tests/ccte_test.cpp +++ b/mcc/tests/ccte_test.cpp @@ -105,6 +105,19 @@ int main() std::cout << "TIME TO ZONE 2: " << vm[1] << "\n"; + std::vector vpt( + 2, {.pair_kind = mcc::MccCoordPairKind::COORDS_KIND_AZZD, .time_point = eqhrz.time_point}); + + ret = pzcont.intersectPZone(eqhrz, &vpt); + std::cout << "ret = " << ret.message() << "\n"; + if (!ret) { + std::cout << "INTERSC POINT 1: AZ = " << mcc::MccAngle(vpt[0].X).sexagesimal() + << ", ZD = " << mcc::MccAngle(vpt[0].Y).sexagesimal() << "\n"; + std::cout << "INTERSC POINT 2: AZ = " << mcc::MccAngle(vpt[1].X).sexagesimal() + << ", ZD = " << mcc::MccAngle(vpt[1].Y).sexagesimal() << "\n"; + } + + std::cout << "\n\n"; MccCCTE_ERFA::meteo_t meteo{.temperature = 10.0, .humidity = 0.7, .pressure = 1010.0};