...
This commit is contained in:
@@ -135,8 +135,8 @@ if (USE_BSPLINE_PCM)
|
||||
endif()
|
||||
|
||||
set(MCC_SRC mcc_concepts.h mcc_constants.h mcc_epoch.h mcc_angle.h mcc_coordinate.h mcc_error.h
|
||||
mcc_traits.h mcc_utils.h
|
||||
mcc_ccte_iers.h mcc_ccte_iers_default.h mcc_ccte_erfa.h mcc_pzone.h mcc_pzone_container.h mcc_pcm.h mcc_telemetry.h)
|
||||
mcc_traits.h mcc_utils.h mcc_ccte_iers.h mcc_ccte_iers_default.h mcc_ccte_erfa.h mcc_pzone.h
|
||||
mcc_pzone_container.h mcc_pcm.h mcc_telemetry.h mcc_serializer.h)
|
||||
|
||||
if (USE_SPDLOG)
|
||||
list(APPEND MCC_SRC mcc_spdlog.h)
|
||||
|
||||
@@ -208,6 +208,10 @@ public:
|
||||
std::lock_guard lock{*_stateMutex};
|
||||
|
||||
_currentState = std::move(state);
|
||||
|
||||
// update refraction model coefficients
|
||||
eraRefco(_currentState.meteo.pressure, _currentState.meteo.temperature, _currentState.meteo.humidity,
|
||||
_currentState.wavelength, &_currentRefractModel.refa, &_currentRefractModel.refb);
|
||||
}
|
||||
|
||||
engine_state_t getStateERFA() const
|
||||
@@ -770,8 +774,8 @@ protected:
|
||||
// NOTE: according to definition of astronomical azimuth it is counted from the South through the West, but
|
||||
// in the ERFA the azimuth is counted from the North through the East!!!
|
||||
//
|
||||
*az = impl::MccAngle(a - std::numbers::pi).normalize<impl::MccAngle::NORM_KIND_0_360>();
|
||||
// *az = MccAngle(a + std::numbers::pi).normalize<MccAngle::NORM_KIND_0_360>();
|
||||
// *az = impl::MccAngle(a - std::numbers::pi).normalize<impl::MccAngle::NORM_KIND_0_360>();
|
||||
*az = impl::MccAngle(a + std::numbers::pi).normalize<impl::MccAngle::NORM_KIND_0_360>();
|
||||
}
|
||||
|
||||
if (zd) {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
// #include <expected>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
@@ -50,10 +50,11 @@ struct MccNullLogger {
|
||||
/* AND CLASS METHODS RETURNED VALUE */
|
||||
|
||||
template <typename T>
|
||||
concept mcc_error_c =
|
||||
std::formattable<T, char> && std::default_initializable<T> && (std::convertible_to<T, bool> || requires(const T t) {
|
||||
(bool)T() == false; // default constucted value must be a "non-error"!
|
||||
});
|
||||
concept mcc_error_c = std::default_initializable<T> && (std::convertible_to<T, bool> || requires(const T t) {
|
||||
// std::formattable<T, char> && std::default_initializable<T> && (std::convertible_to<T, bool>
|
||||
// || requires(const T t) {
|
||||
(bool)T() == false; // default constucted value must be a "non-error"!
|
||||
});
|
||||
|
||||
|
||||
template <mcc_error_c ErrT, mcc_error_c DefErrT>
|
||||
@@ -67,27 +68,27 @@ DefErrT mcc_deduced_err(ErrT const& err, DefErrT const& default_err)
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename VT>
|
||||
concept mcc_retval_c = requires(T t) {
|
||||
//
|
||||
[]<mcc_error_c ErrT>(std::expected<VT, ErrT>) {}(t);
|
||||
};
|
||||
// template <typename T, typename VT>
|
||||
// concept mcc_retval_c = requires(T t) {
|
||||
// //
|
||||
// []<mcc_error_c ErrT>(std::expected<VT, ErrT>) {}(t);
|
||||
// };
|
||||
|
||||
|
||||
// deduce an error from mcc_retval_c and default error value
|
||||
template <typename VT, mcc_retval_c<VT> RetT, mcc_error_c DefErrT>
|
||||
DefErrT mcc_deduced_err(RetT const& ret, DefErrT const& default_err)
|
||||
{
|
||||
if (ret) {
|
||||
return DefErrT{}; // no error
|
||||
}
|
||||
// // deduce an error from mcc_retval_c and default error value
|
||||
// template <typename VT, mcc_retval_c<VT> RetT, mcc_error_c DefErrT>
|
||||
// DefErrT mcc_deduced_err(RetT const& ret, DefErrT const& default_err)
|
||||
// {
|
||||
// if (ret) {
|
||||
// return DefErrT{}; // no error
|
||||
// }
|
||||
|
||||
if constexpr (std::same_as<typename RetT::error_type, DefErrT>) {
|
||||
return ret.error();
|
||||
} else {
|
||||
return default_err;
|
||||
}
|
||||
}
|
||||
// if constexpr (std::same_as<typename RetT::error_type, DefErrT>) {
|
||||
// return ret.error();
|
||||
// } else {
|
||||
// return default_err;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
/* MOUNT CONSTRUCTION-RELATED STUFF */
|
||||
@@ -374,7 +375,7 @@ struct mcc_coord_pair_interface_t {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_coord_pair_c = std::derived_from<T, mcc_coord_pair_interface_t> && requires(T t) {
|
||||
concept mcc_coord_pair_c = std::derived_from<T, mcc_coord_pair_interface_t> && requires(T t, const T t_const) {
|
||||
// the 'T' class must contain static constexpr member of 'pairKind' of some type
|
||||
// (usually just a enum: see mcc_coordinate.h for an example of the implementation)
|
||||
[]() {
|
||||
@@ -386,8 +387,10 @@ concept mcc_coord_pair_c = std::derived_from<T, mcc_coord_pair_interface_t> && r
|
||||
|
||||
// std::constructible_from<T, typename T::x_t const&, typename T::y_t const&>;
|
||||
|
||||
{ t.x() } -> std::same_as<typename T::x_t>;
|
||||
{ t.y() } -> std::same_as<typename T::y_t>;
|
||||
{ t_const.x() } -> std::same_as<typename T::x_t>;
|
||||
{ t_const.y() } -> std::same_as<typename T::y_t>;
|
||||
|
||||
{ t_const.epoch() } -> mcc_coord_epoch_c;
|
||||
|
||||
{ t.setX(std::declval<typename T::x_t const&>()) };
|
||||
{ t.setY(std::declval<typename T::y_t const&>()) };
|
||||
|
||||
@@ -31,5 +31,12 @@ static constexpr DT MCC_INFINITE_DURATION_V =
|
||||
: DT{std::numeric_limits<typename DT::rep>::max()};
|
||||
|
||||
|
||||
// serializer/deserializer delimiters
|
||||
|
||||
// delimiter between items of serializing values sequence
|
||||
static constexpr std::string_view MCC_DEFAULT_SEQ_DELIMITER{";"};
|
||||
|
||||
// delimiter between items of aggregative (multi-element) serializing value
|
||||
static constexpr std::string_view MCC_DEFAULT_ELEM_DELIMITER{","};
|
||||
|
||||
} // namespace mcc
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
template <mcc_coord_epoch_c EpT = MccCelestialCoordEpoch>
|
||||
MccCoordPair(CO_LON_T const& x, CO_LAT_T const& y, EpT const& epoch = EpT::now()) : _x(x), _y(y), _epoch(epoch)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
MccCoordPair(const MccCoordPair&) = default;
|
||||
@@ -85,6 +86,8 @@ public:
|
||||
setX((double)other.x());
|
||||
setY((double)other.y());
|
||||
setEpoch(other.epoch());
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +99,8 @@ public:
|
||||
setX((double)other.x());
|
||||
setY((double)other.y());
|
||||
setEpoch(other.epoch());
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +112,8 @@ public:
|
||||
setX((double)other.x());
|
||||
setY((double)other.y());
|
||||
setEpoch(other.epoch());
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +125,8 @@ public:
|
||||
setX((double)other.x());
|
||||
setY((double)other.y());
|
||||
setEpoch(other.epoch());
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -161,11 +170,15 @@ public:
|
||||
void setX(const CO_LON_T& x)
|
||||
{
|
||||
_x = x;
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
void setY(const CO_LAT_T& y)
|
||||
{
|
||||
_y = y;
|
||||
|
||||
normalize();
|
||||
}
|
||||
|
||||
void setEpoch(mcc_coord_epoch_c auto const& ep)
|
||||
@@ -178,6 +191,26 @@ protected:
|
||||
CO_LAT_T _y;
|
||||
|
||||
MccCelestialCoordEpoch _epoch;
|
||||
|
||||
void normalize()
|
||||
{
|
||||
if constexpr (pairKind != MccCoordPairKind::COORDS_KIND_GENERIC &&
|
||||
pairKind != MccCoordPairKind::COORDS_KIND_XY) {
|
||||
if constexpr (pairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP ||
|
||||
pairKind == MccCoordPairKind::COORDS_KIND_HADEC_OBS) {
|
||||
_x = (double)MccAngle(_x).normalize<MccAngle::NORM_KIND_180_180>();
|
||||
} else { // RA, AZ
|
||||
_x = (double)MccAngle(_x).normalize<MccAngle::NORM_KIND_0_360>();
|
||||
}
|
||||
|
||||
// DEC and ALT is [-90,90] degrees
|
||||
if constexpr (pairKind != MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
_y = (double)MccAngle(_y).normalize<MccAngle::NORM_KIND_90_90>();
|
||||
} else { // ZD id [0, 180] degrees
|
||||
_y = (double)MccAngle(_y).normalize<MccAngle::NORM_KIND_0_180>();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -436,7 +469,7 @@ public:
|
||||
|
||||
|
||||
template <mcc_coord_pair_c PT>
|
||||
operator PT()
|
||||
operator PT() const
|
||||
{
|
||||
if constexpr (PT::pairKind == MccCoordPairKind::COORDS_KIND_LONLAT) { // returns geographic site coordinates
|
||||
std::pair<double, double> pos;
|
||||
@@ -447,7 +480,7 @@ public:
|
||||
|
||||
|
||||
PT res;
|
||||
to(res);
|
||||
toAtSameEpoch(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -457,8 +490,14 @@ public:
|
||||
error_t toAtSameEpoch(PT& cpair, PTs&... cpairs) const
|
||||
{
|
||||
if constexpr (PT::pairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
cpair.setEpoch(_epoch);
|
||||
if (_pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS: set current epoch for result
|
||||
cpair.setEpoch(MccCelestialCoordEpoch::now());
|
||||
} else {
|
||||
cpair.setEpoch(_epoch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto err = toHelper(cpair);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -620,6 +659,16 @@ protected:
|
||||
// HA, DEC to AZ, ALT (AZ from the South through the West)
|
||||
void hadec2azalt(double ha, double dec, double phi, double& az, double& alt) const
|
||||
{
|
||||
eraHd2ae(ha, dec, phi, &az, &alt);
|
||||
// from ERFA "from N" to "from S"
|
||||
if (az > std::numbers::pi) {
|
||||
az -= std::numbers::pi;
|
||||
} else {
|
||||
az += std::numbers::pi;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
const auto cos_phi = std::cos(phi), sin_phi = std::sin(phi);
|
||||
const auto cos_dec = std::cos(dec), sin_dec = std::sin(dec);
|
||||
const auto cos_ha = std::cos(ha), sin_ha = std::sin(ha);
|
||||
@@ -638,7 +687,6 @@ protected:
|
||||
|
||||
az = utils::isEqual(r, 0.0) ? 0.0 : std::atan2(y, x);
|
||||
if (az < 0.0) {
|
||||
// az += std::numbers::pi * 2.0; // to range of [0, 2*PI]
|
||||
az += MCC_TWO_PI; // to range of [0, 2*PI]
|
||||
}
|
||||
|
||||
@@ -649,6 +697,11 @@ protected:
|
||||
// AZ, ALT to HA, DEC (AZ from the South through the West)
|
||||
void azalt2hadec(double az, double alt, double phi, double& ha, double& dec) const
|
||||
{
|
||||
az += std::numbers::pi;
|
||||
eraAe2hd(az, alt, phi, &ha, &dec);
|
||||
|
||||
return;
|
||||
|
||||
const auto cos_phi = std::cos(phi), sin_phi = std::sin(phi);
|
||||
const auto cos_az = std::cos(az), sin_az = std::sin(az);
|
||||
const auto cos_alt = std::cos(alt), sin_alt = std::sin(alt);
|
||||
@@ -724,6 +777,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
if (utils::isEqual(ra_icrs, MCC_TWO_PI)) {
|
||||
ra_icrs = 0.0;
|
||||
}
|
||||
|
||||
|
||||
// here, from APP or OBS to ICRS and exit
|
||||
if (pkind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS &&
|
||||
PT::pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
@@ -896,7 +954,26 @@ protected:
|
||||
return error_t{};
|
||||
};
|
||||
|
||||
return comp_func(pkind); // ran transformation
|
||||
auto err = comp_func(pkind); // ran transformation
|
||||
|
||||
if (ra < 0.0) {
|
||||
ra += MCC_TWO_PI;
|
||||
cpair.setX(ra);
|
||||
}
|
||||
if (az < 0.0) {
|
||||
az += MCC_TWO_PI;
|
||||
cpair.setX(az);
|
||||
}
|
||||
|
||||
// if (utils::isEqual(ra, MCC_TWO_PI)) {
|
||||
// cpair.setX(0.0);
|
||||
// }
|
||||
|
||||
// if (utils::isEqual(az, MCC_TWO_PI)) {
|
||||
// cpair.setX(0.0);
|
||||
// }
|
||||
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
279
mcc_deserializer.h
Normal file
279
mcc_deserializer.h
Normal file
@@ -0,0 +1,279 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF DESERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_constants.h"
|
||||
#include "mcc_error.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccDeserializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_DESERIALIZER,
|
||||
ERROR_INVALID_SERIAL_VALUE,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccDeserializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccDeserializerCategory : public std::error_category {
|
||||
MccDeserializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-DESERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccDeserializerErrorCode err = static_cast<MccDeserializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccDeserializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER:
|
||||
return "error returned by underlying deserializer";
|
||||
case MccDeserializerErrorCode::ERROR_INVALID_SERIAL_VALUE:
|
||||
return "invalid serialized value";
|
||||
case MccDeserializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccDeserializerCategory& get()
|
||||
{
|
||||
static const MccDeserializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccDeserializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_deserializer_interface_t {
|
||||
virtual ~mcc_deserializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT, traits::mcc_input_char_range R, typename ValueT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_deserializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_deserializer_c = std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<impl::MccError> {
|
||||
using typename mcc_deserializer_interface_t<impl::MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
// set delimiter for elements of the range-type serialized value
|
||||
template <traits::mcc_input_char_range R>
|
||||
void setSeqDelimiter(R const& delim)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
setSeqDelimiter(std::string_view{delim});
|
||||
} else {
|
||||
_seqDelimiter.clear();
|
||||
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R getSeqDelimiter() const
|
||||
{
|
||||
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
|
||||
return _seqDelimiter;
|
||||
} else if constexpr (std::ranges::view<R>) {
|
||||
return R{_seqDelimiter.begin(), _seqDelimiter.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_seqDelimiter, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getSeqDelimiter() const
|
||||
{
|
||||
return getSeqDelimiter<std::string>();
|
||||
}
|
||||
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
void setElemDelimiter(R const& delim)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
setElemDelimiter(std::string_view{delim});
|
||||
} else {
|
||||
_elementDelimiter.clear();
|
||||
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R getElemDelimiter() const
|
||||
{
|
||||
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
|
||||
return _elementDelimiter;
|
||||
} else if constexpr (std::ranges::view<R>) {
|
||||
return R{_elementDelimiter.begin(), _elementDelimiter.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_elementDelimiter, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getElemDelimiter() const
|
||||
{
|
||||
return getElemDelimiter<std::string>();
|
||||
}
|
||||
|
||||
protected:
|
||||
MccDeserializerBase() = default;
|
||||
|
||||
// delimiter for sequence of serialized values
|
||||
std::string _seqDelimiter{MCC_DEFAULT_SEQ_DELIMITER};
|
||||
|
||||
// delimiter for aggregative (multi-element) serialized value
|
||||
std::string _elementDelimiter{MCC_DEFAULT_ELEM_DELIMITER};
|
||||
|
||||
template <typename VT, typename R>
|
||||
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
|
||||
error_t deserializingRange(mcc_deserializer_c auto& dsr, traits::mcc_input_char_range auto const& input, R& r) const
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore empy input
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, _seqDelimiter);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
for (auto const& el : r_str) {
|
||||
auto err = dsr(el, val);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
if (it == r.end()) {
|
||||
std::back_inserter(r) = val;
|
||||
it = r.end();
|
||||
} else {
|
||||
*it = val;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
//
|
||||
template <typename VT>
|
||||
class MccDeserializer : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(trimSpaces(input));
|
||||
if (!v.has_value()) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIAL_VALUE;
|
||||
}
|
||||
|
||||
value = v.value();
|
||||
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
|
||||
VT r;
|
||||
if constexpr (traits::mcc_array_c<VT>) {
|
||||
size_t N =
|
||||
std::ranges::size(r) <= std::ranges::size(input) ? std::ranges::size(r) : std::ranges::size(input);
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r[i] = input[i];
|
||||
}
|
||||
if (std::ranges::size(r) > N) {
|
||||
for (size_t i = N; i < std::ranges::size(r); ++i) {
|
||||
r[i] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ranges::copy(input, std::back_inserter(r));
|
||||
}
|
||||
|
||||
value = r;
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using el_t = std::ranges::range_value_t<VT>;
|
||||
|
||||
static_assert(std::ranges::output_range<VT, el_t>, "INVALID RANGE TYPE!!!");
|
||||
|
||||
// no reference or constants allowed
|
||||
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value);
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
|
||||
}
|
||||
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
22
mcc_error.h
22
mcc_error.h
@@ -108,17 +108,17 @@ private:
|
||||
static_assert(mcc::mcc_error_c<mcc::impl::MccError>, "");
|
||||
|
||||
|
||||
// a helper formatter impelementation
|
||||
// // a helper formatter impelementation
|
||||
|
||||
template <typename T>
|
||||
requires std::is_enum_v<T>
|
||||
struct std::formatter<T, char> : std::formatter<std::underlying_type_t<T>, char> {
|
||||
auto format(T e, auto& ctx) const
|
||||
{
|
||||
return formatter<std::underlying_type_t<T>>::format(std::underlying_type_t<T>(e), ctx);
|
||||
}
|
||||
};
|
||||
// template <typename T>
|
||||
// requires std::is_enum_v<T>
|
||||
// struct std::formatter<T, char> : std::formatter<std::underlying_type_t<T>, char> {
|
||||
// auto format(T e, auto& ctx) const
|
||||
// {
|
||||
// return formatter<std::underlying_type_t<T>>::format(std::underlying_type_t<T>(e), ctx);
|
||||
// }
|
||||
// };
|
||||
|
||||
enum class EE : int { A, B, C };
|
||||
// enum class EE : int { A, B, C };
|
||||
|
||||
static_assert(mcc::mcc_error_c<EE>, "");
|
||||
// static_assert(mcc::mcc_error_c<EE>, "");
|
||||
|
||||
872
mcc_serializer.h
872
mcc_serializer.h
@@ -1,45 +1,241 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF SERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <atomic>
|
||||
#include <concepts>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_constants.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_error.h"
|
||||
#include "mcc_traits.h"
|
||||
#include "mcc_utils.h"
|
||||
|
||||
namespace mcc
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccSerializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_SERIALIZER,
|
||||
ERROR_INVALID_EPOCH,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccSerializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccSerializerCategory : public std::error_category {
|
||||
MccSerializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-SERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccSerializerErrorCode err = static_cast<MccSerializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccSerializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER:
|
||||
return "error returned by underlying serializer";
|
||||
case MccSerializerErrorCode::ERROR_INVALID_EPOCH:
|
||||
return "invalid coordinate epoch";
|
||||
case MccSerializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccSerializerCategory& get()
|
||||
{
|
||||
static const MccSerializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccSerializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccSerializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_serializer_interface_t {
|
||||
virtual ~mcc_serializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_serializer_interface_t> SelfT,
|
||||
traits::mcc_output_char_range R,
|
||||
typename ValueT,
|
||||
typename FmtT>
|
||||
requires(std::same_as<std::format_string<ValueT>, FmtT> || std::same_as<std::string_view, FmtT>)
|
||||
mcc_error_c auto operator()(this SelfT&& self, R& output, ValueT const& value, FmtT fmt)
|
||||
RetT operator()(this SelfT&& self, R& output, ValueT const& value, FmtT fmt)
|
||||
{
|
||||
return std::forward<SelfT>(self).operator=(output, value, std::move(fmt));
|
||||
return std::forward<SelfT>(self)(output, value, std::move(fmt));
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_serializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_serializer_c = std::derived_from<T, mcc_serializer_interface_t>;
|
||||
concept mcc_serializer_c = std::derived_from<T, mcc_serializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccSerializerBase : mcc_serializer_interface_t<impl::MccError> {
|
||||
using typename mcc_serializer_interface_t<impl::MccError>::error_t;
|
||||
|
||||
virtual ~MccSerializerBase() = default;
|
||||
|
||||
// set delimiter for elements of the range-type serialized value
|
||||
template <traits::mcc_input_char_range R>
|
||||
void setSeqDelimiter(R const& delim)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
setSeqDelimiter(std::string_view{delim});
|
||||
} else {
|
||||
_seqDelimiter.clear();
|
||||
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R getSeqDelimiter() const
|
||||
{
|
||||
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
|
||||
return _seqDelimiter;
|
||||
} else if constexpr (std::ranges::view<R>) {
|
||||
return R{_seqDelimiter.begin(), _seqDelimiter.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_seqDelimiter, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getSeqDelimiter() const
|
||||
{
|
||||
return getSeqDelimiter<std::string>();
|
||||
}
|
||||
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
void setElemDelimiter(R const& delim)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
setElemDelimiter(std::string_view{delim});
|
||||
} else {
|
||||
_elementDelimiter.clear();
|
||||
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R getElemDelimiter() const
|
||||
{
|
||||
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
|
||||
return _elementDelimiter;
|
||||
} else if constexpr (std::ranges::view<R>) {
|
||||
return R{_elementDelimiter.begin(), _elementDelimiter.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_elementDelimiter, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getElemDelimiter() const
|
||||
{
|
||||
return getElemDelimiter<std::string>();
|
||||
}
|
||||
|
||||
protected:
|
||||
MccSerializerBase() = default;
|
||||
|
||||
// delimiter for sequence of serializing values
|
||||
std::string _seqDelimiter{MCC_DEFAULT_SEQ_DELIMITER};
|
||||
|
||||
// delimiter for aggregative (multi-element) serializing value
|
||||
std::string _elementDelimiter{MCC_DEFAULT_ELEM_DELIMITER};
|
||||
|
||||
template <typename VT, typename R>
|
||||
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
|
||||
error_t serializingRange(mcc_serializer_c auto& sr,
|
||||
R const& r,
|
||||
traits::mcc_output_char_range auto& output,
|
||||
auto fmt) const
|
||||
{
|
||||
size_t i = 0, N = std::ranges::size(r);
|
||||
|
||||
for (auto const& el : r) {
|
||||
auto err = sr(output, el, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
if (++i < N) {
|
||||
std::format_to(std::back_inserter(output), "{}", _seqDelimiter);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
/* fallback template */
|
||||
template <typename VT>
|
||||
class MccSerializer : public mcc_serializer_interface_t
|
||||
class MccSerializer : public details::MccSerializerBase
|
||||
// class MccSerializer : public mcc_serializer_interface_t<impl::MccError>
|
||||
{
|
||||
public:
|
||||
// default delimiter
|
||||
static constexpr std::string_view defaultDelimiter{","};
|
||||
static constexpr std::string_view defaultRangeDelimiter{","};
|
||||
|
||||
typedef impl::MccError error_t;
|
||||
// typedef impl::MccError error_t;
|
||||
|
||||
MccSerializer() = default;
|
||||
|
||||
@@ -52,15 +248,19 @@ public:
|
||||
if constexpr (std::is_null_pointer_v<FmtT>) {
|
||||
std::format_to(std::back_inserter(output), "{}", value);
|
||||
} else if constexpr (traits::mcc_input_char_range<FmtT>) {
|
||||
std::format_to(std::back_inserter(output), fmt, value);
|
||||
} else if constexpr (std::same_as<std::format_string<VT>, FmtT>) {
|
||||
std::string_view sfmt{fmt.begin(), fmt.end()};
|
||||
std::vformat_to(std::back_inserter(output), sfmt, std::make_format_args(value));
|
||||
} else if constexpr (std::same_as<std::format_string<VT>, FmtT>) {
|
||||
std::format_to(std::back_inserter(output), std::move(fmt), value);
|
||||
} else {
|
||||
static_assert(false, "INVALID FORMAT STRING TYPE!!!");
|
||||
}
|
||||
} else if constexpr (std::convertible_to<VT, std::string>) {
|
||||
return MccSerializer<std::string>{}(output, static_cast<std::string>(value), std::move(fmt));
|
||||
auto err = MccSerializer<std::string>{}(output, static_cast<std::string>(value), std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
|
||||
@@ -69,37 +269,77 @@ public:
|
||||
std::string str;
|
||||
std::ranges::copy(value, std::back_inserter(str));
|
||||
|
||||
return MccSerializer<std::string>{}(output, str, std::move(fmt));
|
||||
auto err = MccSerializer<std::string>{}(output, str, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
} else {
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
size_t i = 0, N = std::ranges::size(value);
|
||||
for (auto const& el : value) {
|
||||
error_t err = sr(output, el, std::move(fmt));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (++i < N) {
|
||||
std::format_to(std::back_inserter(output), "{}", _delimiter);
|
||||
}
|
||||
}
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||
}
|
||||
|
||||
return {};
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _delimiter{defaultDelimiter};
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_angle_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public mcc_serializer_interface_t
|
||||
requires(traits::mcc_systime_c<VT> ||
|
||||
(std::ranges::input_range<VT> && traits::mcc_systime_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public details::MccSerializerBase
|
||||
{
|
||||
public:
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
if constexpr (std::is_null_pointer_v<FmtT>) {
|
||||
std::format_to(std::back_inserter(output), "{:%FT%T}", value);
|
||||
} else if constexpr (traits::mcc_input_char_range<FmtT>) {
|
||||
std::string_view sfmt{fmt.begin(), fmt.end()};
|
||||
if (sfmt == "{}") {
|
||||
sfmt = "{:%FT%T}";
|
||||
}
|
||||
std::vformat_to(std::back_inserter(output), sfmt, std::make_format_args(value));
|
||||
} else if constexpr (std::same_as<std::format_string<VT>, FmtT>) {
|
||||
std::string_view sfmt{fmt.get().begin(), fmt.get().end()};
|
||||
if (sfmt == "{}") {
|
||||
std::format_to(std::back_inserter(output), "{:%FT%T}", value);
|
||||
} else {
|
||||
std::format_to(std::back_inserter(output), std::move(fmt), value);
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "INVALID FORMAT STRING TYPE!!!");
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> &&
|
||||
(mcc_angle_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>)))
|
||||
class MccSerializer<VT> : public virtual details::MccSerializerBase
|
||||
// class MccSerializer<VT> : public mcc_serializer_interface_t<impl::MccError>
|
||||
{
|
||||
public:
|
||||
enum SerializedCoordFormat {
|
||||
@@ -113,7 +353,9 @@ public:
|
||||
uint8_t deg_prec = 1; // number of decimal places in arcseconds
|
||||
};
|
||||
|
||||
typedef impl::MccError error_t;
|
||||
// typedef impl::MccError error_t;
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setCoordFormat(SerializedCoordFormat format)
|
||||
{
|
||||
@@ -140,24 +382,12 @@ public:
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
MccSerializer<std::remove_cv_t<std::ranges::range_value_t<VT>>> sr;
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
sr.setCoordFormat(_coordFormat);
|
||||
sr.setCoordPrec(_coordPrec);
|
||||
|
||||
error_t err;
|
||||
size_t i = 0, N = std::ranges::size(value);
|
||||
for (auto const& el : value) {
|
||||
err = sr(output, el, std::move(fmt));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (++i < N) {
|
||||
std::format_to(std::back_inserter(output), " ");
|
||||
}
|
||||
}
|
||||
|
||||
return error_t{};
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
double v = (double)value; // radians
|
||||
std::string sgm;
|
||||
@@ -167,27 +397,565 @@ public:
|
||||
v *= 180.0 / std::numbers::pi;
|
||||
return MccSerializer<double>{}(output, v, std::move(fmt));
|
||||
case MccSerializer::CFMT_SGM_HOURS:
|
||||
sgm = utils::rad2sxg(value, true, _coordPrec.load().hour_prec);
|
||||
sgm = utils::rad2sxg(v, true, _coordPrec.load().hour_prec);
|
||||
break;
|
||||
case MccSerializer::CFMT_SGM_DEGS:
|
||||
sgm = utils::rad2sxg(value, false, _coordPrec.load().deg_prec);
|
||||
sgm = utils::rad2sxg(v, false, _coordPrec.load().deg_prec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return MccSerializer<std::string>{}(output, sgm, std::move(fmt));
|
||||
auto err = MccSerializer<std::string>{}(output, sgm, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<SerializedCoordFormat> _coordFormat{MccSerializer::CFMT_DEGREES};
|
||||
// std::atomic<SerializedCoordFormat> _coordFormat{MccSerializer::CFMT_DEGREES};
|
||||
std::atomic<SerializedCoordFormat> _coordFormat{MccSerializer::CFMT_SGM_DEGS};
|
||||
std::atomic<SexagesimalCoordPrec> _coordPrec{SexagesimalCoordPrec{.hour_prec = 2, .deg_prec = 1}};
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
class MccSerializer<VT> : public mcc_serializer_interface_t
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_epoch_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_coord_epoch_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public virtual details::MccSerializerBase
|
||||
{
|
||||
public:
|
||||
enum TimePointFormat { TP_FORMAT_DATE, TP_FORMAT_MJD, TP_FORMAT_JEPOCH };
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setTimePointFormat(TimePointFormat format)
|
||||
{
|
||||
_tpFormat = format;
|
||||
}
|
||||
|
||||
TimePointFormat getTimePointFormat() const
|
||||
{
|
||||
return _tpFormat;
|
||||
}
|
||||
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
sr.setTimePointFormat(_tpFormat);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else {
|
||||
switch (_tpFormat) {
|
||||
case TP_FORMAT_DATE: {
|
||||
auto utc = value.UTC();
|
||||
auto err = MccSerializer<std::remove_cvref_t<decltype(utc)>>{}(output, utc, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} break;
|
||||
case TP_FORMAT_MJD: {
|
||||
double mjd = value.MJD();
|
||||
auto err = MccSerializer<double>{}(output, mjd, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} break;
|
||||
case TP_FORMAT_JEPOCH: {
|
||||
auto jepoch = value.JEpoch();
|
||||
auto err = MccSerializer<std::remove_cvref_t<decltype(jepoch)>>{}(output, jepoch, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<TimePointFormat> _tpFormat{TP_FORMAT_DATE};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_pair_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_coord_pair_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>,
|
||||
public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccAngle>>,
|
||||
MccSerializer<MccAngle>>
|
||||
// class MccSerializer<VT> : public mcc_serializer_interface_t<MccError>
|
||||
{
|
||||
protected:
|
||||
typedef std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>
|
||||
base_ser_epoch_t;
|
||||
|
||||
typedef std::
|
||||
conditional_t<std::ranges::input_range<VT>, MccSerializer<std::vector<MccAngle>>, MccSerializer<MccAngle>>
|
||||
base_ser_angle_t;
|
||||
|
||||
public:
|
||||
using typename details::MccSerializerBase::error_t;
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
sr.setTimePointFormat(this->_tpFormat);
|
||||
sr.setCoordFormat(this->_coordFormat);
|
||||
sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar: format X[elem-delimiter]Y[elem-delimiter]epoch[elem-delimiter]pair-kind
|
||||
|
||||
// WARNING: still ignore format string!!!
|
||||
|
||||
error_t err;
|
||||
|
||||
// format to sexagesimal form according to celestial coordinate type (general XY-type is skipped)
|
||||
if (this->_coordFormat != base_ser_angle_t::CFMT_DEGREES) {
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
|
||||
if constexpr (VT::pairKind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
VT::pairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // azimuth is in degrees
|
||||
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
} else { // RA or HA are in hours
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
}
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
} else { // here all angles in deciamal degrees
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// format to sexagesimal form according to celestial coordinate type (general XY-type is skipped)
|
||||
// Y-coordinate of the celestial point is always in degrees
|
||||
if (this->_coordFormat != base_ser_angle_t::CFMT_DEGREES) {
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.y()});
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
} else { // here all angles in deciamal degrees
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.y()});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
auto ep = value.epoch();
|
||||
if constexpr (std::convertible_to<decltype(ep), MccCelestialCoordEpoch>) {
|
||||
auto err_e = base_ser_epoch_t::operator()(output, MccCelestialCoordEpoch{ep});
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
} else {
|
||||
MccCelestialCoordEpoch ep1;
|
||||
bool ok = ep1.fromMJD(ep.MJD());
|
||||
if (!ok) {
|
||||
return MccSerializerErrorCode::ERROR_INVALID_EPOCH;
|
||||
}
|
||||
|
||||
auto err_e = (*this)(output, ep1);
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
auto err_s = MccSerializer<std::string_view>{}(output, MccCoordPairKindToStr(VT::pairKind));
|
||||
if (err_s) {
|
||||
return mcc_deduced_err(err_s, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_skypoint_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_skypoint_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>,
|
||||
public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccAngle>>,
|
||||
MccSerializer<MccAngle>>
|
||||
{
|
||||
protected:
|
||||
typedef std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>
|
||||
base_ser_epoch_t;
|
||||
|
||||
typedef std::
|
||||
conditional_t<std::ranges::input_range<VT>, MccSerializer<std::vector<MccAngle>>, MccSerializer<MccAngle>>
|
||||
base_ser_angle_t;
|
||||
|
||||
public:
|
||||
using typename details::MccSerializerBase::error_t;
|
||||
|
||||
enum SkyPointFormat {
|
||||
SKYPOINT_FORMAT_FULL, // return RA_ICRS, DEC_ICRS, RA_APP, DEC_APP, RA_OBS, DEC_OBS, AZ, ZD, HA_APP,
|
||||
// TIME-POINT
|
||||
SKYPOINT_FORMAT_OBS, // return observed coordinates: RA_OBS, DEC_OBS, AZ, ZD, HA_OBS, TIME-POINT
|
||||
SKYPOINT_FORMAT_APP, // return apparent (in vacuo) coordinates: RA_APP, DEC_APP, HA_APP, TIME-POINT
|
||||
SKYPOINT_FORMAT_PAIR // return current stored coordinate pair: X, Y, TIME-POINT, PAIR-KIND
|
||||
};
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setSkyPointFormat(SkyPointFormat format)
|
||||
{
|
||||
_skptFormat = format;
|
||||
}
|
||||
|
||||
SkyPointFormat getSkyPointFormat() const
|
||||
{
|
||||
return _skptFormat;
|
||||
}
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
sr.setTimePointFormat(this->_tpFormat);
|
||||
sr.setCoordFormat(this->_coordFormat);
|
||||
sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
|
||||
auto serialize_pair_func = [&output, this]<typename PT>(PT const& pt) -> error_t {
|
||||
MccSerializer<PT> pt_sr;
|
||||
|
||||
pt_sr.setTimePointFormat(this->_tpFormat);
|
||||
pt_sr.setCoordFormat(this->_coordFormat);
|
||||
pt_sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
auto err = pt_sr(output, pt);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
|
||||
// WARNING: still ignore format string!!!
|
||||
|
||||
auto skpt_fmt = _skptFormat.load();
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_PAIR) {
|
||||
switch (value.pairKind()) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_ICRS());
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_APP());
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_OBS());
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
return serialize_pair_func(value.operator MccSkyHADEC_APP());
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
return serialize_pair_func(value.operator MccSkyHADEC_OBS());
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
return serialize_pair_func(value.operator MccSkyAZZD());
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
return serialize_pair_func(value.operator MccSkyAZALT());
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
return serialize_pair_func(value.operator MccGenXY());
|
||||
default:
|
||||
return serialize_pair_func(value.operator MccGenXY()); // ???????!!!!!!!!!!!
|
||||
}
|
||||
} else {
|
||||
MccSkyRADEC_ICRS radec_icrs;
|
||||
MccSkyRADEC_OBS radec_obs;
|
||||
MccSkyHADEC_OBS hadec_obs;
|
||||
MccSkyRADEC_APP radec_app;
|
||||
MccSkyHADEC_APP hadec_app;
|
||||
MccSkyAZZD azzd;
|
||||
// MccGenXY xy;
|
||||
|
||||
if (value.pairKind() == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
auto ep_now = MccCelestialCoordEpoch::now();
|
||||
radec_obs.setEpoch(ep_now);
|
||||
radec_app.setEpoch(ep_now);
|
||||
hadec_obs.setEpoch(ep_now);
|
||||
hadec_app.setEpoch(ep_now);
|
||||
azzd.setEpoch(ep_now);
|
||||
} else {
|
||||
auto ep = value.epoch();
|
||||
radec_obs.setEpoch(ep);
|
||||
radec_app.setEpoch(ep);
|
||||
hadec_obs.setEpoch(ep);
|
||||
hadec_app.setEpoch(ep);
|
||||
azzd.setEpoch(ep);
|
||||
}
|
||||
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_FULL) { // RA_ICRS, DEC_ICRS, RA_APP, DEC_APP
|
||||
auto err = value.to(radec_icrs, radec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_ICRS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_icrs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_ICRS is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_icrs.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// RA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_APP is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_OBS || skpt_fmt == SKYPOINT_FORMAT_FULL) { // RA_OBS, DEC_OBS, AZ, ZD
|
||||
auto err = value.to(radec_obs, azzd);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_OBS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_obs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_OBS, AZ and ZD are in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_obs.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)azzd.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)azzd.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_FULL) { // HA_APP
|
||||
auto err = value.to(hadec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// HA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_OBS) { // HA_OBS
|
||||
auto err = value.to(hadec_obs);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// HA_OBS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_obs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_APP) { // RA_APP, DEC_APP, HA_APP
|
||||
auto err = value.to(radec_app, hadec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_APP is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// HA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
|
||||
|
||||
// epoch of app/obs coordinates
|
||||
auto ep = value.epoch();
|
||||
if constexpr (std::convertible_to<decltype(ep), MccCelestialCoordEpoch>) {
|
||||
auto err_e = base_ser_epoch_t::operator()(output, MccCelestialCoordEpoch{ep});
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
} else {
|
||||
MccCelestialCoordEpoch ep1;
|
||||
bool ok = ep1.fromMJD(ep.MJD());
|
||||
if (!ok) {
|
||||
return MccSerializerErrorCode::ERROR_INVALID_EPOCH;
|
||||
}
|
||||
|
||||
auto err_e = (*this)(output, ep1);
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<SkyPointFormat> _skptFormat{SKYPOINT_FORMAT_FULL};
|
||||
};
|
||||
|
||||
|
||||
@@ -199,7 +967,7 @@ static_assert(mcc_serializer_c<MccSerializer<impl::MccAngle>>, "!!!");
|
||||
static_assert(std::atomic<MccSerializer<impl::MccAngle>::SerializedCoordFormat>::is_always_lock_free, "!!!");
|
||||
static_assert(std::atomic<MccSerializer<impl::MccAngle>::SexagesimalCoordPrec>::is_always_lock_free, "!!!");
|
||||
|
||||
static_assert(traits::mcc_formattable<impl::MccAngle>, "!!!");
|
||||
static_assert(std::formattable<impl::MccAngle, char>, "!!!");
|
||||
|
||||
void f()
|
||||
{
|
||||
@@ -209,4 +977,4 @@ void f()
|
||||
s(str, impl::MccAngleALT{1.1});
|
||||
}
|
||||
|
||||
} // namespace mcc
|
||||
} // namespace mcc::impl
|
||||
|
||||
@@ -60,9 +60,9 @@ concept mcc_range_of_output_char_range =
|
||||
|
||||
// https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts)
|
||||
template <typename T>
|
||||
concept mcc_formattable = requires(T v) { [](T vv) { return std::format("{}", vv); }(v); };
|
||||
// concept mcc_formattable =
|
||||
// requires(T v, std::format_context ctx) { std::formatter<std::remove_cvref_t<T>>().format(v, ctx); };
|
||||
concept mcc_formattable =
|
||||
requires(T v, std::format_context ctx) { std::formatter<std::remove_cvref_t<T>>().format(v, ctx); };
|
||||
// concept mcc_formattable = requires(T v) { [](T vv) { return std::format("{}", vv); }(v); };
|
||||
|
||||
|
||||
// from https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types
|
||||
|
||||
11
mcc_utils.h
11
mcc_utils.h
@@ -247,6 +247,17 @@ static R rad2sxg(double ang, bool hms = false, int prec = 2)
|
||||
// round to given precision of arcseconds/seconds
|
||||
degs = std::round(degs * 3600.0 * term) / term / 3600.0;
|
||||
|
||||
if constexpr (NORM) {
|
||||
if (hms) {
|
||||
if (isEqual(degs, 24.0)) {
|
||||
degs = 0.0;
|
||||
}
|
||||
} else {
|
||||
if (isEqual(degs, 360.0)) {
|
||||
degs = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto d = std::trunc(degs);
|
||||
auto s = (degs - d) * 60.0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// #include <mcc_ccte_erfa.h>
|
||||
#include <mcc_coordinate.h>
|
||||
|
||||
#include <mcc_serializer.h>
|
||||
|
||||
using namespace mcc::impl;
|
||||
|
||||
@@ -19,6 +19,21 @@ static skypt_t::ccte_t::engine_state_t saoras{.meteo{.temperature = 0.0, .humidi
|
||||
|
||||
static_assert(mcc::mcc_angle_c<double>, "!!!!!!!!!!!!");
|
||||
|
||||
|
||||
template <typename VT>
|
||||
void serialize(VT const& value)
|
||||
{
|
||||
MccSerializer<VT> ser;
|
||||
std::string s;
|
||||
|
||||
auto err = ser(s, value);
|
||||
if (err) {
|
||||
std::cout << "SERIALIZing ERR: " << err << "\n";
|
||||
} else {
|
||||
std::cout << "SERIALIZED: " << s << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
skypt_t::cctEngine.setStateERFA(saoras);
|
||||
@@ -60,9 +75,12 @@ int main()
|
||||
azzd.setX(111.0_degs), azzd.setY(111.0_degs);
|
||||
azalt.setX(111.0_degs), azalt.setY(111.0_degs);
|
||||
hadec_obs.setX(111.0_degs), hadec_obs.setY(111.0_degs);
|
||||
radec_app.setX(111.0_degs), radec_app.setY(111.0_degs);
|
||||
|
||||
pt = radec_obs;
|
||||
pt.to(icrs, azzd, hadec_obs);
|
||||
// pt.to(icrs, azzd, hadec_obs, radec_app);
|
||||
pt.to(icrs, radec_app);
|
||||
pt.to(radec_obs, hadec_obs, azzd);
|
||||
|
||||
std::cout << "\n\nFROM OBSERVED TO ICRS:\n";
|
||||
std::cout << "OBS COORD EPOCH: " << radec_obs.epoch().UTC() << "\n";
|
||||
@@ -78,9 +96,50 @@ int main()
|
||||
std::cout << "HA_OBS = " << hadec_obs.x().sexagesimal(true) << "\n";
|
||||
std::cout << "AZ = " << azzd.x().sexagesimal() << "\n";
|
||||
std::cout << "ZD = " << azzd.y().sexagesimal() << "\n";
|
||||
std::cout << "RA_APP = " << radec_app.x().sexagesimal(true) << "\n";
|
||||
std::cout << "DEC_APP = " << radec_app.y().sexagesimal() << "\n";
|
||||
|
||||
azalt = pt;
|
||||
std::cout << "ALT = " << azalt.y().sexagesimal() << "\n";
|
||||
|
||||
std::cout << "\nIN DEGREES:\n";
|
||||
std::cout << "RA_ICRS = " << icrs.x().degrees() << "\n";
|
||||
std::cout << "DEC_ICRS = " << icrs.y().degrees() << "\n";
|
||||
std::cout << "RA_OBS = " << radec_obs.x().degrees() << "\n";
|
||||
std::cout << "DEC_OBS = " << radec_obs.y().degrees() << "\n";
|
||||
std::cout << "HA_OBS = " << hadec_obs.x().degrees() << "\n";
|
||||
std::cout << "AZ = " << azzd.x().degrees() << "\n";
|
||||
std::cout << "ZD = " << azzd.y().degrees() << "\n";
|
||||
std::cout << "RA_APP = " << radec_app.x().degrees() << "\n";
|
||||
std::cout << "DEC_APP = " << radec_app.y().degrees() << "\n";
|
||||
|
||||
|
||||
std::cout << "\n\nSERIALIZATION TEST:\n";
|
||||
|
||||
|
||||
double v = 7.7;
|
||||
|
||||
std::cout << "\tfor 'double' type: ";
|
||||
serialize(v);
|
||||
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(radec_obs);
|
||||
|
||||
radec_app = pt;
|
||||
// pt.to(radec_app);
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(radec_app);
|
||||
|
||||
azzd = pt;
|
||||
// pt.to(azzd);
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(azzd);
|
||||
|
||||
// pt.from(icrs);
|
||||
pt = radec_obs;
|
||||
|
||||
std::cout << "\tfor 'sky point' type: ";
|
||||
serialize(pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user