diff --git a/include/mcc/mcc_deserializer.h b/include/mcc/mcc_deserializer.h index e556af4..afae187 100644 --- a/include/mcc/mcc_deserializer.h +++ b/include/mcc/mcc_deserializer.h @@ -126,7 +126,8 @@ protected: return MccDeserializerErrorCode::ERROR_OK; } - auto r_str = std::views::split(input, params.seq_delim); + // auto r_str = std::views::split(input, params.seq_delim); + auto r_str = std::views::split(input, params.elem_delim); VT val; auto it = r.begin(); diff --git a/include/mcc/mcc_pcm.h b/include/mcc/mcc_pcm.h index 4838f21..5f75a99 100644 --- a/include/mcc/mcc_pcm.h +++ b/include/mcc/mcc_pcm.h @@ -106,6 +106,24 @@ class is_error_code_enum : public true_type namespace mcc::impl { +// The routine generates a sequence of length 'innerN'+2 elements. +// Th e first element is 'start_border' and the last one is 'stop_border' +// (i.e. it returns at least 2-elements std::vector) +// 'innerN' is a number of inner elements +static std::vector mccGenerateBsplineKnots(double start_border, double stop_border, size_t innerN) +{ + std::vector res(innerN + 2); + res.front() = start_border; + res.back() = stop_border; + + if (innerN) { + const double step = (stop_border - start_border) / (innerN + 1); + std::ranges::for_each(std::views::iota(1, (int)innerN + 1), + [&](auto const& i) { res[i] = start_border + i * step; }); + } + + return res; +} // type of PCM corrections (algorithm used): // PCM_TYPE_GEOMETRY - "classic" geometry-based correction coefficients diff --git a/include/mcc/mcc_pzone.h b/include/mcc/mcc_pzone.h index 4f0baa1..c34d956 100644 --- a/include/mcc/mcc_pzone.h +++ b/include/mcc/mcc_pzone.h @@ -13,12 +13,14 @@ #include "mcc_concepts.h" #include "mcc_constants.h" #include "mcc_coordinate.h" +#include "mcc_deserializer.h" +#include "mcc_serializer.h" namespace mcc::impl { -enum class MccPZoneErrorCode : int { ERROR_OK, ERROR_NULLPTR, ERROR_COORD_TRANSFROM, ERROR_PCM_COMP }; +enum class MccPZoneErrorCode : int { ERROR_OK, ERROR_NULLPTR, ERROR_COORD_TRANSFROM, ERROR_NO_PCM, ERROR_PCM_COMP }; } // namespace mcc::impl @@ -56,6 +58,8 @@ struct MccPZoneCategory : public std::error_category { return "input argument os nullptr"; case MccPZoneErrorCode::ERROR_COORD_TRANSFROM: return "coordinate transformation error"; + case MccPZoneErrorCode::ERROR_NO_PCM: + return "PCM was not set"; case MccPZoneErrorCode::ERROR_PCM_COMP: return "PCM computation error"; default: @@ -89,6 +93,7 @@ public: MccAltLimitPZ(mcc_angle_c auto const& alt_limit, mcc_angle_c auto const& latitude) : _altLimit(MccAngle(alt_limit).normalize()), + _latitude(MccAngle::normalizeAngle(latitude)), _cosALim(cos(_altLimit)), _sinAlim(sin(_altLimit)), _cosLat(cos(latitude)), @@ -106,6 +111,29 @@ public: : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE" : "ALTLIMIT-UNKNOWN"; + template + T altLimit() const + requires(!std::derived_from) + { + return _altLimit; + } + + MccAngle altLimit() const + { + return _altLimit; + } + + template + T latitude() const + requires(!std::derived_from) + { + return _latitude; + } + + MccAngle latitude() const + { + return _latitude; + } error_t inPZone(mcc_skypoint_c auto const& coords, bool* result) { @@ -230,7 +258,7 @@ public: protected: double _altLimit, _cosALim, _sinAlim; - double _cosLat, _sinLat, _absLat, _latLim; + double _latitude, _cosLat, _sinLat, _absLat, _latLim; bool doesObjectReachZone(const double& dec_app) { @@ -322,14 +350,83 @@ protected: }; +/* + to be serialized in format: + ALT-LIMITLATITUDE + */ +template +struct MccSerializer> : MccSerializerBase { + constexpr static std::string_view serializerName{"MCC-ALTITUDE-PZONE-SERIALIZER"}; -/* co-longitude axis (HA or AZ) limit switch prohibited zone */ + template + error_t operator()(traits::mcc_output_char_range auto& output, + MccAltLimitPZ const& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + MccSerializer aser; + + auto err = aser(output, value.altLimit(), params); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + std::format_to(std::back_inserter(output), "{}", params.seq_delim); + + err = aser(output, value.latitude(), params); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + return MccSerializerErrorCode::ERROR_OK; + } +}; + +template +struct MccDeserializer> : MccDeserializerBase { + static constexpr std::string_view deserializerName{"MCC-ALTITUDE-PZONE-DESERIALIZER"}; + + template + error_t operator()(traits::mcc_input_char_range auto const& input, + MccAltLimitPZ& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + std::string_view s; + MccDeserializer ades; + + auto seq = std::views::split(params.seq_delim); + if (std::ranges::size(seq) < 2) { + s = utils::trimSpaces(seq, utils::TrimType::TRIM_BOTH); + MccAngle alt, lat; + + auto err = ades(input, alt, params); + if (err) { + return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; + } + + err = ades(input, lat, params); + if (err) { + return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; + } + + value = MccAltLimitPZ{alt, lat}; + } else { + return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE; + } + + return MccDeserializerErrorCode::ERROR_OK; + } +}; + + + +/* co-longitude axis (HA or AZ) and co-latitude (DEC, ZD) limit switch prohibited zone */ template class MccAxisLimitSwitchPZ : public mcc_pzone_interface_t { public: - static_assert(AXIS_KIND == MccCoordKind::COORDS_KIND_AZ || AXIS_KIND == MccCoordKind::COORDS_KIND_HA_OBS, + static_assert(AXIS_KIND == MccCoordKind::COORDS_KIND_AZ || AXIS_KIND == MccCoordKind::COORDS_KIND_HA_OBS || + AXIS_KIND == MccCoordKind::COORDS_KIND_ZD || AXIS_KIND == MccCoordKind::COORDS_KIND_DEC_OBS, "UNSUPPORTED AXIS TYPE!"); typedef std::error_code error_t; @@ -339,33 +436,84 @@ public: static constexpr MccProhibitedZonePolicy pzPolicy = MccProhibitedZonePolicy::PZ_POLICY_FLIP; // - // min_limit_val and max_limit_val are hardware encoder angles in radians! + // min_limit_val and max_limit_val are hardware encoder angles! + // pcm is nullptr or pointer to mcc_pcm_c // - MccAxisLimitSwitchPZ(mcc_angle_c auto const& min_limit_val, - mcc_angle_c auto const& max_limit_val, - mcc_pcm_c auto* pcm) + template + MccAxisLimitSwitchPZ(mcc_angle_c auto const& min_limit_val, mcc_angle_c auto const& max_limit_val, PCM_T pcm) + requires(std::is_null_pointer_v || mcc_pcm_c>) : _minLimit(min_limit_val), _maxLimit(max_limit_val) { - _correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) { - struct pcm_res_t { - double pcmX, pcmY; + if constexpr (std::is_null_pointer_v) { + _correctForPCM = [](MccSkyPoint const&, MccGenXY*) -> error_t { return MccPZoneErrorCode::ERROR_NO_PCM; }; + } else { + _correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) { + struct pcm_res_t { + double pcmX, pcmY; + }; + + pcm_res_t res; + + auto err = pcm->computeInversePCM(skypt, &res, hw_coords); + + return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP); }; - - pcm_res_t res; - - auto err = pcm->computeInversePCM(skypt, &res, hw_coords); - - return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP); - }; + } } - static constexpr std::string_view pzoneName = axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ_AXIS-LIMITSWITCH_ZONE" - : axisKind == MccCoordKind::COORDS_KIND_HA_OBS - ? "HA_AXIS-LIMITSWITCH_ZONE" - : "UKNOWN"; + static constexpr std::string_view pzoneName = + axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ-AXIS-LIMITSWITCH-ZONE" + : axisKind == MccCoordKind::COORDS_KIND_HA_OBS ? "HA-AXIS-LIMITSWITCH-ZONE" + : axisKind == MccCoordKind::COORDS_KIND_ZD ? "ZD-AXIS-LIMITSWITCH-ZONE" + : axisKind == MccCoordKind::COORDS_KIND_DEC_OBS ? "DEC-AXIS-LIMITSWITCH-ZONE" + : "UKNOWN"; + template + T minLimit() const + requires(!std::derived_from) + { + return _minLimit; + } + + MccAngle minLimit() const + { + return _minLimit; + } + + template + T maxLimit() const + requires(!std::derived_from) + { + return _maxLimit; + } + + MccAngle maxLimit() const + { + return _maxLimit; + } + + template + void setPCM(PCM_T pcm) + requires(std::is_null_pointer_v || mcc_pcm_c>) + { + if constexpr (std::is_null_pointer_v) { + _correctForPCM = [](MccSkyPoint const&, MccGenXY*) -> error_t { return MccPZoneErrorCode::ERROR_NO_PCM; }; + } else { + _correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) { + struct pcm_res_t { + double pcmX, pcmY; + }; + + pcm_res_t res; + + auto err = pcm->computeInversePCM(skypt, &res, hw_coords); + + return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP); + }; + } + } error_t inPZone(mcc_skypoint_c auto const& coords, bool* result) { @@ -439,6 +587,9 @@ protected: time_ang = (_maxLimit - x) / MCC_SIDERAL_TO_UT1_RATIO; // to UT1 scale } } else if constexpr (AXIS_KIND == MccCoordKind::COORDS_KIND_AZ) { + static_assert(false, "NOT IMPLEMENTED YET!!!"); + } else { + static_assert(false, "NOT IMPLEMENTED YET!!!"); } std::chrono::nanoseconds ns{ @@ -452,4 +603,74 @@ protected: }; +/* + to be serialized in format: + MIN_LIMITMAX_LIMIT + */ +template +struct MccSerializer> : MccSerializerBase { + constexpr static std::string_view serializerName{"MCC-AXIS-LIMIT-SWITCH-SERIALIZER"}; + + template + error_t operator()(traits::mcc_output_char_range auto& output, + MccAxisLimitSwitchPZ const& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + MccSerializer aser; + + auto err = aser(output, value.minLimit(), params); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + std::format_to(std::back_inserter(output), "{}", params.seq_delim); + + err = aser(output, value.maxLimit(), params); + if (err) { + return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + } + + + return MccSerializerErrorCode::ERROR_OK; + } +}; + + +template +struct MccDeserializer> : MccDeserializerBase { + static constexpr std::string_view deserializerName{"MCC-AXIS-LIMIT-SWITCH-DESERIALIZER"}; + + template + error_t operator()(traits::mcc_input_char_range auto const& input, + MccAxisLimitSwitchPZ& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + std::string_view s; + MccDeserializer ades; + + auto seq = std::views::split(params.seq_delim); + if (std::ranges::size(seq) < 2) { + s = utils::trimSpaces(seq, utils::TrimType::TRIM_BOTH); + MccAngle minLim, maxLim; + + auto err = ades(input, minLim, params); + if (err) { + return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; + } + + err = ades(input, maxLim, params); + if (err) { + return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; + } + + // WARNING: the class below is created without the PCM-class pointer!!! + value = MccAxisLimitSwitchPZ{minLim, maxLim}; + } else { + return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE; + } + + return MccDeserializerErrorCode::ERROR_OK; + } +}; + } // namespace mcc::impl