This commit is contained in:
Timur A. Fatkhullin
2026-02-06 00:09:15 +03:00
parent 6352865610
commit 97b908838c
5 changed files with 269 additions and 46 deletions

View File

@@ -280,15 +280,15 @@ public:
}
// latitude and longitude
template <mcc_angle_c LAT_T, mcc_angle_c LON_T>
void geoPosition(std::pair<LAT_T, LON_T>* coords) const
// longitude and latitude
template <mcc_angle_c LON_T, mcc_angle_c LAT_T>
void geoPosition(std::pair<LON_T, LAT_T>* coords) const
{
std::lock_guard lock{*_stateMutex};
if (coords) {
coords->first = _currentState.lat;
coords->second = _currentState.lon;
coords->first = _currentState.lon;
coords->second = _currentState.lat;
}
}

View File

@@ -473,11 +473,11 @@ struct mcc_skypoint_interface_t {
return std::forward<SelfT>(self).refractInverseCorrection(dZ);
}
// returns apparent sideral time (Greenwich) for the epoch of the celestial point
// returns apparent sideral time (Greenwich or local) for the epoch of the celestial point
template <std::derived_from<mcc_skypoint_interface_t> SelfT>
auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st)
auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st, bool is_local)
{
return std::forward<SelfT>(self).appSideralTime(st);
return std::forward<SelfT>(self).appSideralTime(st, is_local);
}
// returns equation of origins for the epoch of the celestial point
@@ -571,7 +571,7 @@ concept mcc_pcm_c = std::derived_from<T, mcc_pcm_interface_t<typename T::error_t
// static constexpr uint16_t HW_MOVE_ERROR = 555;
// }
template <typename T>
concept mcc_hardware_movement_state_c = requires {
concept mcc_hardware_movement_state_c = std::formattable<T, char> && requires {
[]() {
// // mount axes were stopped
// [[maybe_unused]] static constexpr auto v0 = T::HW_MOVE_STOPPED;
@@ -621,7 +621,6 @@ concept mcc_hardware_movement_state_c = requires {
template <typename T>
concept mcc_hardware_state_c = requires(T state) {
// encoder co-longitude and co-latiitude positions, as well as its measurement time point
// the given constrains on coordinate pair kind can be used to deduce mount type
requires mcc_coord_pair_c<decltype(state.XY)> &&
(decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_GENERIC ||
decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_XY);

View File

@@ -475,7 +475,7 @@ public:
std::pair<double, double> pos;
cctEngine.geoPosition(&pos);
return MccGeoLONLAT(pos.second, pos.first);
return MccGeoLONLAT(pos.first, pos.second);
}
@@ -581,10 +581,9 @@ public:
}
error_t appSideralTime(mcc_angle_c auto* st) const
error_t appSideralTime(mcc_angle_c auto* st, bool is_local = false) const
{
// return Greenwich apparent sideral time since epoch is UTC
return cctEngine.apparentSideralTime(_epoch, st, false);
return cctEngine.apparentSideralTime(_epoch, st, is_local);
}
@@ -735,6 +734,16 @@ protected:
static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_UNKNOWN, "UNSUPPORTED SKY POINT TRANSFORMATION!");
if constexpr (PT::pairKind == MccCoordPairKind::COORDS_KIND_LONLAT) { // returns geographic site coordinates
std::pair<double, double> pos;
cctEngine.geoPosition(&pos);
cpair.setX(pos.first);
cpair.setY(pos.second);
return error_t{};
}
if (_pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS &&
PT::pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS to ICRS - just copy and exit
cpair = PT(typename PT::x_t(_x), typename PT::y_t(_y));

277
mcc_ser.h
View File

@@ -158,8 +158,10 @@ template <typename VT>
struct MccSerializer : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-FALLBACK-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
if constexpr (std::formattable<VT, char>) {
} else if constexpr (std::convertible_to<VT, std::string>) {
@@ -205,8 +207,10 @@ struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-SYSTIME-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
std::vformat_to(std::back_inserter(output), params.systime_format, std::make_format_args(value));
@@ -220,8 +224,10 @@ template <typename VT>
struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-ANGLE-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
double v = (double)value; // radians (see mcc_angle_c concept)
std::string sgm;
@@ -264,8 +270,10 @@ template <mcc_coord_epoch_c VT>
struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-COORD-EPOCH-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
double jd;
@@ -304,11 +312,12 @@ template <mcc_coord_pair_c VT>
struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-COORD-PAIR-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
std::conditional_t<std::is_null_pointer_v<ParamsT>, std::nullptr_t, mcc_serialization_params_t> pars =
std::is_null_pointer_v<ParamsT> ? nullptr : params;
auto pars = params;
pars.norm_sxgm = true;
pars.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
@@ -358,8 +367,10 @@ template <mcc_skypoint_c VT>
struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-SKYPOINT-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
auto serialize_cpair = [&]<typename T>(T& cp) {
auto ccte_err = value.to(cp);
@@ -423,52 +434,256 @@ template <mcc_telemetry_data_c VT>
struct MccSerializer<VT> : MccSerializerBase {
constexpr static std::string_view serializerName{"MCC-TELEMETRY-DATA-SERIALIZER"};
template <typename ParamsT = std::nullptr_t>
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, ParamsT const& params = nullptr)
template <typename ParamsT = mcc_serialization_params_t>
error_t operator()(traits::mcc_output_char_range auto& output,
VT const& value,
ParamsT const& params = mcc_serialization_params_t{})
{
// FORMAT: RA_OBS_MOUNT, DEC_OBS_MOUNT, RA_APP_MOUNT, DEC_APP_MOUNT, HA_APP_MOUNT, AZ_MOUNT, ZD_MOUNT,
// REFR_CORR_MOUNT, LAST, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, TIMEPOINT
// REFR_CORR_MOUNT, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, LAST, EO, TIMEPOINT,
// STATUS
// NOTE: One must assume that the returned RA coordinates are in format of underlying celestial coordinate
// transformation engine used in the mcc_skypoint_c class implementation. E.g. ERFA-library uses the
// CIO-based representation of RA
std::conditional_t<std::is_null_pointer_v<ParamsT>, std::nullptr_t, mcc_serialization_params_t> pars =
std::is_null_pointer_v<ParamsT> ? nullptr : params;
auto pars_h = params;
pars.norm_sxgm = true;
pars.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
auto pars_d = params;
std::string ra_obs, ra_app, ha, last, ra_app_tg;
MccSkyRADEC_OBS r_obs;
MccSkyRADEC_APP r_app;
pars_h.norm_sxgm = true;
pars_h.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
pars_d.norm_sxgm = true;
pars_d.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
MccSkyRADEC_OBS rd_obs;
MccSkyRADEC_APP rd_app;
MccSkyHADEC_APP hd_app;
MccSkyAZZD azzd;
// quantities in hour representation
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars);
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars_h);
// quantities in degree representation
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars_d);
MccSerializer<MccAngle> ang_sr;
// RA_OBS_MOUNT
auto ccte_err = value.mountPos.toAtSameEpoch(r_obs);
// RA_OBS_MOUNT, DEC_OBS_MOUNT
auto ccte_err = value.mountPos.toAtSameEpoch(rd_obs);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
auto err = ang_sr(ra_obs, r_obs, pars);
auto err = ang_sr(output, rd_obs.x(), pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
// RA_APP_MOUNT
ccte_err = value.mountPos.toAtSameEpoch(r_app);
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, rd_obs.y(), pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// RA_APP_MOUNT, DEC_APP_MOUNT
ccte_err = value.mountPos.toAtSameEpoch(rd_app);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(ra_app, r_app, pars);
err = ang_sr(output, rd_app.x(), pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, rd_app.y(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// HA_APP_MOUNT
ccte_err = value.mountPos.toAtSameEpoch(hd_app);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, hd_app.x(), pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// AZ_MOUNT, ZD_MOUNT
ccte_err = value.mountPos.toAtSameEpoch(azzd);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, azzd.x(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, azzd.y(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// refraction correction
MccAngle ang;
ccte_err = value.mountPos.refractCorrection(&ang);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, ang, pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// encoder X and Y
err = ang_sr(output, value.hwState.XY.x(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, value.hwState.XY.y(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// PCM X and Y
err = ang_sr(output, value.pcmCorrection.pcmX(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, value.pcmCorrection.pcmY(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// RA_APP_TAG, DEC_APP_TAG
ccte_err = value.targetPos.toAtSameEpoch(rd_app);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, rd_app.x(), pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, rd_app.y(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// AZ_TAG, ZD_TAG
ccte_err = value.targetPos.toAtSameEpoch(azzd);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, azzd.x(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
err = ang_sr(output, azzd.y(), pars_d);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// LAST, local apparent sideral time
ccte_err = value.mountPos.appSideralTime(&ang, true);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, ang, pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// EO, equation of origins
ccte_err = value.mountPos.EO(&ang);
if (ccte_err) {
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
}
err = ang_sr(output, ang, pars_h);
if (err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// coordinates epoch
auto ep_err = MccSerializer<MccCelestialCoordEpoch>{}(output, value.mountPos.epoch(), pars_d);
if (ep_err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
MccSerializerBase::addElemDelimiter(output, pars_h);
// status (it must be formattable, see mcc_concepts.h)
auto st_err =
MccSerializer<decltype(value.hwState.movementState)>{}(output, value.hwState.movementState, pars_d);
if (st_err) {
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
return MccSerializerErrorCode::ERROR_OK;
}
};

View File

@@ -163,7 +163,7 @@ static constexpr std::string_view MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER{","};
template <typename T>
concept mcc_serialization_params_c = requires(T t) {
concept mcc_serialization_params_c = std::copyable<T> && requires(T t) {
requires traits::mcc_output_char_range<decltype(t.seq_delim)>;
requires traits::mcc_output_char_range<decltype(t.elem_delim)>;