This commit is contained in:
Timur A. Fatkhullin 2025-10-24 12:16:44 +03:00
parent e6b4604bfa
commit 47c57dca72

View File

@ -504,4 +504,283 @@ static_assert(mcc_celestial_point_c<MccCelestialPoint>, "");
static_assert(mcc_telemetry_data_c<MccTelemetryData>, ""); static_assert(mcc_telemetry_data_c<MccTelemetryData>, "");
/* DEFAULT SERIALIZER/DESERIALIZER FOR COORDINATE-RELATED CLASSES */
// base class
class MccCoordinateDeserializer
{
public:
virtual ~MccCoordinateDeserializer() = default;
template <traits::mcc_input_char_range R>
void setDelimiter(R&& delim)
{
if constexpr (std::is_pointer_v<std::decay_t<R>>) {
setDelimiter(std::string_view(delim));
} else {
_delimiter.clear();
std::ranges::copy(std::forward<R>(delim), std::back_inserter(_delimiter));
}
}
template <std::derived_from<MccCoordinateDeserializer> SelfT, traits::mcc_input_char_range IR, typename VT>
std::error_code operator()(this SelfT&& self, IR&& bytes, VT& value)
{
if constexpr (std::same_as<std::remove_cvref_t<SelfT>, MccCoordinateDeserializer>) {
static_assert(false, "!!!!!");
} else {
return std::forward<SelfT>(self)(std::forward<IR>(bytes), value);
}
}
protected:
std::string _delimiter{","};
template <traits::mcc_input_char_range IR>
std::vector<std::string_view> splitToElements(IR&& bytes)
{
std::vector<std::string_view> res;
auto els = std::views::split(std::forward<IR>(bytes), _delimiter);
for (auto const& el : els) {
std::back_inserter(res) = std::string_view(el.begin(), el.end());
}
return res;
}
template <traits::mcc_input_char_range IR, mcc_celestial_point_c T>
std::error_code parseTimePoint(const IR& bytes, T& cp)
{
MccCelestialCoordEpoch cep;
bool ok = cep.fromCharRange(bytes);
if (!ok) {
return std::make_error_code(std::errc::invalid_argument);
}
mcc_tp2tp(cep.UTC(), cp.time_point);
return {};
}
};
// base class
class MccCoordinateSerializer
{
public:
enum SerializedCoordFormat {
CFMT_DEGREES, // floating-point representation in degrees
CFMT_SGM // sexagesimal representation: HH:MM:SS.SSSSSS (hours:minutes:seconds) or DD:MM:SS.SSSSS
// (degrees:arcmins::arcsecs)
};
struct SexagesimalCoordPrec {
uint8_t hour_prec = 2; // number of decimal places in hour seconds
uint8_t deg_prec = 1; // number of decimal places in arcseconds
};
MccCoordinateSerializer() = default;
MccCoordinateSerializer(SerializedCoordFormat fmt, SexagesimalCoordPrec prec)
{
setFormat(fmt);
setPrecision(std::move(prec));
}
virtual ~MccCoordinateSerializer() = default;
void setFormat(SerializedCoordFormat fmt)
{
_currentFormat = fmt;
}
void setPrecision(SexagesimalCoordPrec prec)
{
_currentPrec = std::move(prec);
}
template <traits::mcc_input_char_range R>
void setDelimiter(R&& delim)
{
if constexpr (std::is_pointer_v<std::decay_t<R>>) {
setDelimiter(std::string_view(delim));
} else {
_delimiter.clear();
std::ranges::copy(std::forward<R>(delim), std::back_inserter(_delimiter));
}
}
template <std::derived_from<MccCoordinateSerializer> SelfT, typename T, traits::mcc_output_char_range OR>
void operator()(this SelfT&& self, const T& value, OR& bytes)
{
if constexpr (std::same_as<std::remove_cvref_t<SelfT>, MccCoordinateSerializer>) {
static_assert(false, "!!!!!");
} else {
std::forward<SelfT>(self)(value, bytes);
}
}
protected:
SerializedCoordFormat _currentFormat{CFMT_DEGREES};
SexagesimalCoordPrec _currentPrec{.hour_prec = 2, .deg_prec = 1};
std::string _delimiter{","};
template <mcc_celestial_point_c T, traits::mcc_output_char_range OR>
void serializePairKindTimePoint(const T& value, OR& bytes)
{
std::format_to(std::back_inserter(bytes), "{0:}{1:}{2:}{3:%F}T{3:%T}", _delimiter,
MccCoordPairKindToStr(value.pair_kind), _delimiter, value.time_point);
}
template <traits::mcc_output_char_range OR, std::convertible_to<double>... Ts>
void toDegrees(OR& bytes, double angle, const Ts&... angles)
{
std::format_to(std::back_inserter(bytes), "{}", MccAngle(angle).degrees());
if constexpr (sizeof...(Ts)) {
std::format_to(std::back_inserter(bytes), "{}", _delimiter);
toDegrees(bytes, angles...);
}
}
template <traits::mcc_output_char_range OR, std::convertible_to<double>... Ts>
void toSexagesimalHour(OR& bytes, double angle, const Ts&... angles)
{
std::format_to(std::back_inserter(bytes), "{}", MccAngle(angle).sexagesimal(true, _currentPrec.hour_prec));
if constexpr (sizeof...(Ts)) {
std::format_to(std::back_inserter(bytes), "{}", _delimiter);
toSexagesimalHour(bytes, angles...);
}
}
template <traits::mcc_output_char_range OR, std::convertible_to<double>... Ts>
void toSexagesimalDeg(OR& bytes, double angle, const Ts&... angles)
{
std::format_to(std::back_inserter(bytes), "{}", MccAngle(angle).sexagesimal(false, _currentPrec.deg_prec));
if constexpr (sizeof...(Ts)) {
std::format_to(std::back_inserter(bytes), "{}", _delimiter);
toSexagesimalHour(bytes, angles...);
}
}
};
class MccCelestialPointSerializer : public MccCoordinateSerializer
{
public:
template <mcc_celestial_point_c T, traits::mcc_output_char_range OR>
void operator()(const T& value, OR& bytes)
{
if (_currentFormat == SerializedCoordFormat::CFMT_DEGREES) {
// std::format_to(std::back_inserter(bytes), "{}{}{}", MccAngle(value.X).degrees(), _delimiter,
// MccAngle(value.Y).degrees());
toDegrees(bytes, value.X, value.Y);
} else {
switch (value.pair_kind) {
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
// std::format_to(std::back_inserter(bytes), "{}{}",
// MccAngle(value.X).sexagesimal(true, _currentPrec.hour_prec), _delimiter);
toSexagesimalHour(bytes, value.X);
break;
default:
// std::format_to(std::back_inserter(bytes), "{}{}",
// MccAngle(value.X).sexagesimal(false, _currentPrec.deg_prec), _delimiter);
toSexagesimalDeg(bytes, value.X);
}
// std::format_to(std::back_inserter(bytes), "{}",
// MccAngle(value.Y).sexagesimal(false, _currentPrec.deg_prec));
std::format_to(std::back_inserter(bytes), "{}", _delimiter);
toSexagesimalDeg(bytes, value.Y);
}
serializePairKindTimePoint(value, bytes);
}
};
class MccCelestialPointDeserializer : public MccCoordinateDeserializer
{
public:
template <traits::mcc_input_char_range IR, mcc_celestial_point_c T>
std::error_code operator()(IR&& bytes, T& value)
{
auto els = splitToElements(std::forward<IR>(bytes));
if (els.size() < 2) { // at least coordinate pair must be given
return std::make_error_code(std::errc::invalid_argument);
}
MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
if (els.size() > 2) { // pair of coordinates and the pair kind
pt.pair_kind = MccCoordStrToPairKind(els[2]);
if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
return std::make_error_code(std::errc::invalid_argument);
}
}
if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
// J2000.0: 11:58:55.816 1 January 2000 UTC
auto tp = std::chrono::sys_days(std::chrono::year_month_day(std::chrono::January / std::chrono::day(1) /
std::chrono::year(2000))) +
std::chrono::hours(11) + std::chrono::minutes(58) + std::chrono::milliseconds(55816);
mcc_tp2tp(tp, pt.time_point);
} else {
if (els.size() > 3) { // coordinates epoch is given
auto err = parseTimePoint(els[3], pt);
if (err) {
return err;
}
} else { // no time point - use NOW
mcc_tp2tp(std::chrono::system_clock::now(), pt.time_point);
}
}
std::optional<double> ang1, ang2;
switch (pt.pair_kind) {
// if sexagesimal then hours:minutes:seconds form
case mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
case mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP:
case mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP:
ang1 = mcc::utils::parsAngleString(els[0], true);
break;
default:
// if sexagesimal then degrees:arcminutes:arcseconds form
ang1 = mcc::utils::parsAngleString(els[0]);
}
if (!ang1) {
return std::make_error_code(std::errc::invalid_argument);
}
ang2 = mcc::utils::parsAngleString(els[1]);
if (!ang2) {
return std::make_error_code(std::errc::invalid_argument);
}
pt.X = MccAngle(ang1.value(), mcc::MccDegreeTag{});
pt.Y = MccAngle(ang2.value(), mcc::MccDegreeTag{});
mcc_copy_celestial_point(pt, &value);
}
};
class MccEqtHrzCoordsSerializer : public MccCoordinateSerializer
{
};
class MccEqtHrzCoordsDeserializer : public MccCoordinateDeserializer
{
};
} // namespace mcc } // namespace mcc