mcc_pzone.h: add serializer/deserializer of the implemented prohibited

zone clases
mcc_pcm.h: add mccGenerateBsplineKnots function
mcc_deserializer.h: fixes
This commit is contained in:
2026-05-21 12:20:32 +03:00
parent 47ba7342e7
commit 4b5a390987
3 changed files with 263 additions and 23 deletions

View File

@@ -126,7 +126,8 @@ protected:
return MccDeserializerErrorCode::ERROR_OK; 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; VT val;
auto it = r.begin(); auto it = r.begin();

View File

@@ -106,6 +106,24 @@ class is_error_code_enum<mcc::impl::MccDefaultPCMErrorCode> : public true_type
namespace mcc::impl 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<double> mccGenerateBsplineKnots(double start_border, double stop_border, size_t innerN)
{
std::vector<double> 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): // type of PCM corrections (algorithm used):
// PCM_TYPE_GEOMETRY - "classic" geometry-based correction coefficients // PCM_TYPE_GEOMETRY - "classic" geometry-based correction coefficients

View File

@@ -13,12 +13,14 @@
#include "mcc_concepts.h" #include "mcc_concepts.h"
#include "mcc_constants.h" #include "mcc_constants.h"
#include "mcc_coordinate.h" #include "mcc_coordinate.h"
#include "mcc_deserializer.h"
#include "mcc_serializer.h"
namespace mcc::impl 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 } // namespace mcc::impl
@@ -56,6 +58,8 @@ struct MccPZoneCategory : public std::error_category {
return "input argument os nullptr"; return "input argument os nullptr";
case MccPZoneErrorCode::ERROR_COORD_TRANSFROM: case MccPZoneErrorCode::ERROR_COORD_TRANSFROM:
return "coordinate transformation error"; return "coordinate transformation error";
case MccPZoneErrorCode::ERROR_NO_PCM:
return "PCM was not set";
case MccPZoneErrorCode::ERROR_PCM_COMP: case MccPZoneErrorCode::ERROR_PCM_COMP:
return "PCM computation error"; return "PCM computation error";
default: default:
@@ -89,6 +93,7 @@ public:
MccAltLimitPZ(mcc_angle_c auto const& alt_limit, mcc_angle_c auto const& latitude) MccAltLimitPZ(mcc_angle_c auto const& alt_limit, mcc_angle_c auto const& latitude)
: _altLimit(MccAngle(alt_limit).normalize<MccAngle::NORM_KIND_90_90>()), : _altLimit(MccAngle(alt_limit).normalize<MccAngle::NORM_KIND_90_90>()),
_latitude(MccAngle::normalizeAngle<MccAngle::NORM_KIND_90_90>(latitude)),
_cosALim(cos(_altLimit)), _cosALim(cos(_altLimit)),
_sinAlim(sin(_altLimit)), _sinAlim(sin(_altLimit)),
_cosLat(cos(latitude)), _cosLat(cos(latitude)),
@@ -106,6 +111,29 @@ public:
: KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE" : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
: "ALTLIMIT-UNKNOWN"; : "ALTLIMIT-UNKNOWN";
template <mcc_angle_c T>
T altLimit() const
requires(!std::derived_from<T, MccAngle>)
{
return _altLimit;
}
MccAngle altLimit() const
{
return _altLimit;
}
template <mcc_angle_c T>
T latitude() const
requires(!std::derived_from<T, MccAngle>)
{
return _latitude;
}
MccAngle latitude() const
{
return _latitude;
}
error_t inPZone(mcc_skypoint_c auto const& coords, bool* result) error_t inPZone(mcc_skypoint_c auto const& coords, bool* result)
{ {
@@ -230,7 +258,7 @@ public:
protected: protected:
double _altLimit, _cosALim, _sinAlim; double _altLimit, _cosALim, _sinAlim;
double _cosLat, _sinLat, _absLat, _latLim; double _latitude, _cosLat, _sinLat, _absLat, _latLim;
bool doesObjectReachZone(const double& dec_app) bool doesObjectReachZone(const double& dec_app)
{ {
@@ -322,14 +350,83 @@ protected:
}; };
/*
to be serialized in format:
ALT-LIMIT<seq-delim>LATITUDE
*/
template <MccAltLimitKind KIND>
struct MccSerializer<MccAltLimitPZ<KIND>> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-ALTITUDE-PZONE-SERIALIZER"};
/* co-longitude axis (HA or AZ) limit switch prohibited zone */ template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
MccAltLimitPZ<KIND> const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
MccSerializer<MccAngle> 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 <MccAltLimitKind KIND>
struct MccDeserializer<MccAltLimitPZ<KIND>> : MccDeserializerBase {
static constexpr std::string_view deserializerName{"MCC-ALTITUDE-PZONE-DESERIALIZER"};
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_input_char_range auto const& input,
MccAltLimitPZ<KIND>& value,
ParamsT const& params = mcc_serialization_params_t{})
{
std::string_view s;
MccDeserializer<MccAngle> 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<KIND>{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 <MccCoordKind AXIS_KIND> template <MccCoordKind AXIS_KIND>
class MccAxisLimitSwitchPZ : public mcc_pzone_interface_t<std::error_code> class MccAxisLimitSwitchPZ : public mcc_pzone_interface_t<std::error_code>
{ {
public: 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!"); "UNSUPPORTED AXIS TYPE!");
typedef std::error_code error_t; typedef std::error_code error_t;
@@ -339,13 +436,17 @@ public:
static constexpr MccProhibitedZonePolicy pzPolicy = MccProhibitedZonePolicy::PZ_POLICY_FLIP; 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, template <typename PCM_T>
mcc_angle_c auto const& max_limit_val, MccAxisLimitSwitchPZ(mcc_angle_c auto const& min_limit_val, mcc_angle_c auto const& max_limit_val, PCM_T pcm)
mcc_pcm_c auto* pcm) requires(std::is_null_pointer_v<PCM_T> || mcc_pcm_c<std::remove_pointer_t<PCM_T>>)
: _minLimit(min_limit_val), _maxLimit(max_limit_val) : _minLimit(min_limit_val), _maxLimit(max_limit_val)
{ {
if constexpr (std::is_null_pointer_v<PCM_T>) {
_correctForPCM = [](MccSkyPoint const&, MccGenXY*) -> error_t { return MccPZoneErrorCode::ERROR_NO_PCM; };
} else {
_correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) { _correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) {
struct pcm_res_t { struct pcm_res_t {
double pcmX, pcmY; double pcmX, pcmY;
@@ -358,14 +459,61 @@ public:
return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP); return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP);
}; };
} }
}
static constexpr std::string_view pzoneName = axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ_AXIS-LIMITSWITCH_ZONE" static constexpr std::string_view pzoneName =
: axisKind == MccCoordKind::COORDS_KIND_HA_OBS axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ-AXIS-LIMITSWITCH-ZONE"
? "HA_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"; : "UKNOWN";
template <mcc_angle_c T>
T minLimit() const
requires(!std::derived_from<T, MccAngle>)
{
return _minLimit;
}
MccAngle minLimit() const
{
return _minLimit;
}
template <mcc_angle_c T>
T maxLimit() const
requires(!std::derived_from<T, MccAngle>)
{
return _maxLimit;
}
MccAngle maxLimit() const
{
return _maxLimit;
}
template <typename PCM_T>
void setPCM(PCM_T pcm)
requires(std::is_null_pointer_v<PCM_T> || mcc_pcm_c<std::remove_pointer_t<PCM_T>>)
{
if constexpr (std::is_null_pointer_v<PCM_T>) {
_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) 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 time_ang = (_maxLimit - x) / MCC_SIDERAL_TO_UT1_RATIO; // to UT1 scale
} }
} else if constexpr (AXIS_KIND == MccCoordKind::COORDS_KIND_AZ) { } 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{ std::chrono::nanoseconds ns{
@@ -452,4 +603,74 @@ protected:
}; };
/*
to be serialized in format:
MIN_LIMIT<seq-delim>MAX_LIMIT
*/
template <MccCoordKind AXIS_KIND>
struct MccSerializer<MccAxisLimitSwitchPZ<AXIS_KIND>> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-AXIS-LIMIT-SWITCH-SERIALIZER"};
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
MccAxisLimitSwitchPZ<AXIS_KIND> const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
MccSerializer<MccAngle> 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 <MccCoordKind AXIS_KIND>
struct MccDeserializer<MccAxisLimitSwitchPZ<AXIS_KIND>> : MccDeserializerBase {
static constexpr std::string_view deserializerName{"MCC-AXIS-LIMIT-SWITCH-DESERIALIZER"};
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_input_char_range auto const& input,
MccAxisLimitSwitchPZ<AXIS_KIND>& value,
ParamsT const& params = mcc_serialization_params_t{})
{
std::string_view s;
MccDeserializer<MccAngle> 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<AXIS_KIND>{minLim, maxLim};
} else {
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
}
return MccDeserializerErrorCode::ERROR_OK;
}
};
} // namespace mcc::impl } // namespace mcc::impl