...
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>, "");
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user