...
This commit is contained in:
parent
e6b4604bfa
commit
47c57dca72
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user