...
This commit is contained in:
parent
c45d17b236
commit
b99263a014
@ -18,7 +18,7 @@
|
||||
namespace asibfm700
|
||||
{
|
||||
|
||||
typedef mcc::astrom::erfa::MccMountAstromEngineERFA<mcc::MccAngle> AsibFM700AstromEngine;
|
||||
typedef mcc::astrom::erfa::MccMountAstromEngineERFA AsibFM700AstromEngine;
|
||||
|
||||
typedef mcc::MccMountDefaultPEC<mcc::MccMountType::FORK_TYPE> AsibFM700PointingErrorCorrection;
|
||||
|
||||
|
||||
@ -10,9 +10,9 @@ AsibFM700Mount::AsibFM700Mount(AsibFM700Config config, std::shared_ptr<spdlog::l
|
||||
base_gm_t({_currentConfig.astromEngineState},
|
||||
{_currentConfig.hardwareConfig},
|
||||
{_currentConfig.pecData},
|
||||
AsibFM700Telemetry{_astromEngine, _pec, _hardware},
|
||||
slew_model_t{_telemetry, _hardware, _pzFuncs},
|
||||
guiding_model_t{_telemetry, _hardware, _pzFuncs})
|
||||
AsibFM700Telemetry{&_astromEngine, &_pec, &_hardware},
|
||||
slew_model_t{&_telemetry, &_hardware, &_pzFuncs},
|
||||
guiding_model_t{&_telemetry, &_hardware, &_pzFuncs})
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -119,9 +119,9 @@ public:
|
||||
traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T,
|
||||
// traits::mcc_tuple_c PZ_T,
|
||||
typename... LoggerCtorArgTs>
|
||||
MccSimpleGuidingModel(TELEMETRY_T& telemetry,
|
||||
HARDWARE_T& hardware,
|
||||
PZ_T& prohibited_zone,
|
||||
MccSimpleGuidingModel(TELEMETRY_T* telemetry,
|
||||
HARDWARE_T* hardware,
|
||||
PZ_T* prohibited_zone,
|
||||
LoggerCtorArgTs&&... ctor_args)
|
||||
requires(!std::same_as<LoggerT, MccNullLogger>)
|
||||
: LoggerT(std::forward<LoggerCtorArgTs>(ctor_args)...)
|
||||
@ -131,16 +131,16 @@ public:
|
||||
init(telemetry, hardware, prohibited_zone);
|
||||
}
|
||||
|
||||
template <traits::mcc_mount_telemetry_c TELEMETRY_T,
|
||||
traits::mcc_mount_hardware_c HARDWARE_T,
|
||||
traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T
|
||||
// traits::mcc_tuple_c PZ_T
|
||||
>
|
||||
MccSimpleGuidingModel(TELEMETRY_T& telemetry, HARDWARE_T& hardware, PZ_T& prohibited_zone)
|
||||
requires(std::same_as<LoggerT, MccNullLogger>)
|
||||
{
|
||||
init(telemetry, hardware, prohibited_zone);
|
||||
}
|
||||
// template <traits::mcc_mount_telemetry_c TELEMETRY_T,
|
||||
// traits::mcc_mount_hardware_c HARDWARE_T,
|
||||
// traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T
|
||||
// // traits::mcc_tuple_c PZ_T
|
||||
// >
|
||||
// MccSimpleGuidingModel(TELEMETRY_T& telemetry, HARDWARE_T& hardware, PZ_T& prohibited_zone)
|
||||
// requires(std::same_as<LoggerT, MccNullLogger>)
|
||||
// {
|
||||
// init(telemetry, hardware, prohibited_zone);
|
||||
// }
|
||||
|
||||
|
||||
MccSimpleGuidingModel(MccSimpleGuidingModel&& other)
|
||||
@ -184,22 +184,22 @@ protected:
|
||||
|
||||
|
||||
|
||||
error_t init(auto& telemetry, auto& hardware, auto& prohibited_zones)
|
||||
error_t init(auto* p_telemetry, auto* p_hardware, auto* p_prohibited_zones)
|
||||
{
|
||||
// deduce controls types
|
||||
// deduce controls types
|
||||
using hardware_t = decltype(hardware);
|
||||
using telemetry_t = decltype(telemetry);
|
||||
using hardware_t = decltype(*p_hardware);
|
||||
using telemetry_t = decltype(*p_telemetry);
|
||||
static_assert(traits::mcc_mount_default_telemetry_c<telemetry_t>,
|
||||
"TELEMETRY CLASS MUST BE A DESCENDANT OF 'MccMountTelemetry'!");
|
||||
|
||||
using astrom_engine_t = typename telemetry_t::astrom_engine_t;
|
||||
|
||||
static constexpr size_t Nzones = std::tuple_size_v<decltype(prohibited_zones)>;
|
||||
static constexpr size_t Nzones = std::tuple_size_v<decltype(*p_prohibited_zones)>;
|
||||
|
||||
const auto p_telemetry = &telemetry;
|
||||
const auto p_hardware = &hardware;
|
||||
const auto p_prohibited_zones = &prohibited_zones;
|
||||
// const auto p_telemetry = &telemetry;
|
||||
// const auto p_hardware = &hardware;
|
||||
// const auto p_prohibited_zones = &prohibited_zones;
|
||||
|
||||
_guidingFunc = [p_telemetry, p_hardware, p_prohibited_zones, this](guiding_point_t guiding_point) {
|
||||
_stopRequested = false;
|
||||
|
||||
@ -107,11 +107,6 @@ inline std::error_code make_error_code(MccMountAstromEngineERFAErrorCode ec)
|
||||
|
||||
|
||||
|
||||
/* A concept for ERFA-library compatible type to represent anglular quantities */
|
||||
template <typename T>
|
||||
concept mcc_erfa_angle_t = std::constructible_from<T, double> && std::convertible_to<T, double>;
|
||||
|
||||
template <mcc_erfa_angle_t AngleT = MccAngle>
|
||||
class MccMountAstromEngineERFA
|
||||
{
|
||||
public:
|
||||
@ -119,6 +114,9 @@ public:
|
||||
|
||||
typedef std::error_code error_t;
|
||||
|
||||
/* use of the same type for representation of celestial and geodetic coordinates, celestial angles (e.g. P.A.),
|
||||
* and sideral time */
|
||||
typedef double coord_t;
|
||||
|
||||
// meteo parameters (to compute refraction)
|
||||
struct meteo_t {
|
||||
@ -136,9 +134,9 @@ public:
|
||||
|
||||
double wavelength = DEFAULT_WAVELENGTH; // observed wavelength in mkm
|
||||
|
||||
AngleT lat = "00:00:00"_dms; // site latitude
|
||||
AngleT lon = "00:00:00"_dms; // site longitude
|
||||
double elev = 0.0; // site elevation (in meters)
|
||||
coord_t lat = "00:00:00"_dms; // site latitude
|
||||
coord_t lon = "00:00:00"_dms; // site longitude
|
||||
double elev = 0.0; // site elevation (in meters)
|
||||
|
||||
mcc::astrom::iers::MccLeapSeconds _leapSeconds{};
|
||||
mcc::astrom::iers::MccIersBulletinA _bulletinA{};
|
||||
@ -152,13 +150,10 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/* use of the same type for representation of celestial and geodetic coordinates, celestial angles (e.g. P.A.),
|
||||
* and sideral time */
|
||||
typedef AngleT coord_t;
|
||||
|
||||
typedef AngleT sideral_time_t;
|
||||
typedef AngleT pa_t;
|
||||
typedef AngleT eo_t;
|
||||
typedef coord_t sideral_time_t;
|
||||
typedef coord_t pa_t;
|
||||
typedef coord_t eo_t;
|
||||
|
||||
struct refract_result_t {
|
||||
double refa, refb;
|
||||
@ -556,6 +551,170 @@ public:
|
||||
return MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
error_t coord2coord(MccCoordPairKind coord_from_kind,
|
||||
coord_t x_from,
|
||||
coord_t y_from,
|
||||
time_point_t time_point_from,
|
||||
MccCoordPairKind coord_to_kind,
|
||||
coord_t& x_to,
|
||||
coord_t& y_to,
|
||||
time_point_t time_point_to)
|
||||
{
|
||||
error_t ret = MccMountAstromEngineERFAErrorCode::ERROR_OK;
|
||||
|
||||
// no convertion
|
||||
if (time_point_from == time_point_to && coord_from_kind == coord_to_kind) {
|
||||
x_to = x_from;
|
||||
y_to = y_from;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
juldate_t jd;
|
||||
eo_t eo;
|
||||
coord_t ra, dec, ha, az, alt;
|
||||
sideral_time_t lst;
|
||||
|
||||
auto lst_eo = [&]() {
|
||||
ret = greg2jul(time_point_from, jd);
|
||||
if (!ret) {
|
||||
ret = apparentSiderTime(jd, lst, true);
|
||||
if (!ret) {
|
||||
ret = eqOrigins(jd, eo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// special case: to ICRS from apparent
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZALT ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
//
|
||||
ret = greg2jul(time_point_from, jd);
|
||||
if (!ret) {
|
||||
ret = obs2icrs(coord_from_kind, x_from, y_from, jd, x_to, y_to);
|
||||
}
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// special case: from ICRS to apparent
|
||||
if (coord_from_kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZALT ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP ||
|
||||
coord_to_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
//
|
||||
ret = greg2jul(time_point_to, jd);
|
||||
if (!ret) {
|
||||
ret = icrs2obs(x_from, y_from, jd, ra, dec, ha, az, alt, eo);
|
||||
|
||||
if (!ret) {
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
||||
x_to = az;
|
||||
y_to = alt;
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
x_to = az;
|
||||
y_to = std::numbers::pi / 2.0 - alt;
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
|
||||
x_to = ra;
|
||||
y_to = dec;
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
x_to = ha;
|
||||
y_to = dec;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// from apparent to apparent
|
||||
if (time_point_from != time_point_to) { // first, convert 'from' coordinates to ICRS
|
||||
ret = greg2jul(time_point_from, jd);
|
||||
if (!ret) {
|
||||
ret = obs2icrs(coord_from_kind, x_from, y_from, jd, ra, dec);
|
||||
if (!ret) { // from ICRS to required
|
||||
return coord2coord(MccCoordPairKind::COORDS_KIND_RADEC_ICRS, ra, dec, time_point_from,
|
||||
coord_to_kind, x_to, y_to, time_point_to);
|
||||
}
|
||||
}
|
||||
} else { // same time points
|
||||
if (coord_from_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
|
||||
// first, compute HA from CIO-based RA!!!
|
||||
lst_eo();
|
||||
if (!ret) {
|
||||
ha = lst - x_from + eo;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
||||
ret = hadec2azalt(ha, y_from, x_to, y_to);
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
ret = hadec2azalt(ha, y_from, x_to, y_to);
|
||||
if (!ret) {
|
||||
y_to = std::numbers::pi / 2.0 - y_to;
|
||||
}
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
x_to = ha;
|
||||
y_to = y_from;
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
} else if (coord_from_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
||||
ret = hadec2azalt(x_from, y_from, x_to, y_to);
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
ret = hadec2azalt(x_from, y_from, x_to, y_to);
|
||||
if (!ret) {
|
||||
y_to = std::numbers::pi / 2.0 - y_to;
|
||||
}
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
|
||||
lst_eo();
|
||||
if (!ret) {
|
||||
x_to = lst - x_from + eo;
|
||||
y_to = y_from;
|
||||
}
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
} else if (coord_from_kind == MccCoordPairKind::COORDS_KIND_AZALT) {
|
||||
if (coord_to_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
|
||||
ret = azalt2hadec(x_from, y_from, x_to, y_to);
|
||||
if (!ret) {
|
||||
lst_eo();
|
||||
if (!ret) {
|
||||
x_to = lst - x_to + eo;
|
||||
}
|
||||
}
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
x_to = x_from;
|
||||
y_to = std::numbers::pi / 2.0 - y_from;
|
||||
} else if (coord_to_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
ret = azalt2hadec(x_from, y_from, x_to, y_to);
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
} else if (coord_from_kind == MccCoordPairKind::COORDS_KIND_AZZD) {
|
||||
return coord2coord(MccCoordPairKind::COORDS_KIND_AZALT, std::move(x_from),
|
||||
std::numbers::pi / 2.0 - y_to, time_point_from, coord_to_kind, x_to, y_to,
|
||||
time_point_to);
|
||||
} else {
|
||||
ret = MccMountAstromEngineERFAErrorCode::ERROR_UNSUPPORTED_COORD_PAIR;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* helper mathods */
|
||||
|
||||
@ -577,4 +736,4 @@ protected:
|
||||
} // namespace mcc::astrom::erfa
|
||||
|
||||
|
||||
static_assert(mcc::traits::mcc_astrom_engine_c<mcc::astrom::erfa::MccMountAstromEngineERFA<>>, "");
|
||||
static_assert(mcc::traits::mcc_astrom_engine_c<mcc::astrom::erfa::MccMountAstromEngineERFA>, "");
|
||||
|
||||
@ -98,6 +98,43 @@ concept mcc_logger_c = requires(T t, const T t_const) {
|
||||
};
|
||||
|
||||
|
||||
/* A CONCEPT FOR COORDINATE REPRESENTATION */
|
||||
|
||||
// it is a fundametal floating-point type or
|
||||
// a class that can be constructed from or converted to the double fundametal type
|
||||
template <typename T>
|
||||
concept mcc_coord_t = std::floating_point<T> || (std::convertible_to<T, double> && std::constructible_from<T, double>);
|
||||
|
||||
|
||||
/* A CONCEPT FOR UTC TIME POINT REPRESENTATION */
|
||||
|
||||
// it is a std::chrono::sys_time<Duration> or
|
||||
// fundamental arithmetic type that represent number of seconds after the 00:00:00 of 1 January 1970 (UNIX time)
|
||||
template <typename T>
|
||||
concept mcc_utc_time_point_c = mcc_systime_c<T> || std::is_arithmetic_v<T>;
|
||||
|
||||
/* A CONCEPT FOR CLASS TO REPRESENT CELESTIAL POINT */
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_celestial_point_c = requires(T t) {
|
||||
// a type to represent UTC time point of coordinates
|
||||
// it's clear that this makes sense for apparent coordinates
|
||||
typename T::time_point_t;
|
||||
|
||||
// coordinates pair type (e.g. IRCS RA,DEC, Az,Alt and so on)
|
||||
requires std::same_as<decltype(t.coordPairKind), MccCoordPairKind>;
|
||||
|
||||
typename T::coord_t;
|
||||
|
||||
// co-longitude (e.g. RA or Az)
|
||||
requires std::same_as<decltype(t.x), typename T::coord_t>;
|
||||
|
||||
// co-latitude (e.g. DEC or ZD)
|
||||
requires std::same_as<decltype(t.y), typename T::coord_t>;
|
||||
};
|
||||
|
||||
|
||||
/* ASTROMETRY-RELATED COMPUTATION ENGINE */
|
||||
|
||||
template <typename T>
|
||||
@ -128,10 +165,10 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
|
||||
} -> std::same_as<typename T::error_t>;
|
||||
|
||||
// observed place to ICRS RA and DEC: obs2icrs(type, x, y, jd, ra_icrs, dec_icrs)
|
||||
// (x,y) = (AZ, ZD) if type = MccCoordPairKind::COORDS_KIND_AZZD
|
||||
// (x,y) = (AZ, ALT) if type = MccCoordPairKind::COORDS_KIND_AZALT
|
||||
// (x,y) = (HA, DEC) if type = MccCoordPairKind::COORDS_KIND_HADEC_APP
|
||||
// (x,y) = (RA, DEC) if type = MccCoordPairKind::COORDS_KIND_RADEC_APP
|
||||
// (x, y) = (AZ, ZD) if type == MccCoordPairKind::COORDS_KIND_AZZD
|
||||
// (x, y) = (AZ, ALT) if type == MccCoordPairKind::COORDS_KIND_AZALT
|
||||
// (x, y) = (HA, DEC) if type == MccCoordPairKind::COORDS_KIND_HADEC_APP
|
||||
// (x, y) = (RA, DEC) if type == MccCoordPairKind::COORDS_KIND_RADEC_APP
|
||||
{
|
||||
t.obs2icrs(std::declval<MccCoordPairKind>(), std::declval<typename T::coord_t>(),
|
||||
std::declval<typename T::coord_t>(), std::declval<typename T::juldate_t>(),
|
||||
@ -157,6 +194,26 @@ concept mcc_astrom_engine_c = requires(T t, const T t_const) {
|
||||
std::declval<typename T::pa_t&>())
|
||||
} -> std::same_as<typename T::error_t>;
|
||||
|
||||
|
||||
// transform coordinates according to its pair types and time points (a high-level wrapper):
|
||||
//
|
||||
// coord2coord(coord_pair_kind_from, x_from, y_from, time_point_from, coord_pair_kind_to, x_to, y_to, time_point_to)
|
||||
//
|
||||
// (x_*, y_*) = (AZ, ZD) if coord_pair_kind_* == MccCoordPairKind::COORDS_KIND_AZZD
|
||||
// (x_*, y_*) = (AZ, ALT) if coord_pair_kind_* == MccCoordPairKind::COORDS_KIND_AZALT
|
||||
// (x_*, y_*) = (HA, DEC) if coord_pair_kind_* == MccCoordPairKind::COORDS_KIND_HADEC_APP (apparent)
|
||||
// (x_*, y_*) = (RA, DEC) if coord_pair_kind_* == MccCoordPairKind::COORDS_KIND_RADEC_APP (apparent)
|
||||
// (x_*, y_*) = (RA, DEC) if coord_pair_kind_* == MccCoordPairKind::COORDS_KIND_RADEC_ICRS (ICRS)
|
||||
//
|
||||
// if coord_pair_kind_* and time_point_* are equal then x_to = x_from, y_to = y_from
|
||||
{
|
||||
t.coord2coord(std::declval<MccCoordPairKind>(), std::declval<typename T::coord_t>(),
|
||||
std::declval<typename T::coord_t>(), std::declval<typename T::time_point_t>(),
|
||||
std::declval<MccCoordPairKind>(), std::declval<typename T::coord_t&>(),
|
||||
std::declval<typename T::coord_t&>(), std::declval<typename T::time_point_t>())
|
||||
} -> std::same_as<typename T::error_t>;
|
||||
|
||||
|
||||
// compute equation of origins
|
||||
{
|
||||
t.eqOrigins(std::declval<typename T::juldate_t>(), std::declval<typename T::eo_t&>())
|
||||
@ -355,23 +412,6 @@ concept mcc_mount_telemetry_c = requires(T t, const T t_const) {
|
||||
};
|
||||
|
||||
|
||||
/* A CONCEPT FOR CLASS TO REPRESENT CELESTIAL POINT */
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_celestial_point_c = requires(T t) {
|
||||
// input coordinates pair type (e.g. IRCS RA,DEC, Az,Alt and so on)
|
||||
requires std::same_as<decltype(t.coordPairKind), MccCoordPairKind>;
|
||||
|
||||
typename T::coord_t;
|
||||
|
||||
// co-longitude (e.g. RA or Az)
|
||||
requires std::same_as<decltype(t.x), typename T::coord_t>;
|
||||
|
||||
// co-latitude (e.g. DEC or ZD)
|
||||
requires std::same_as<decltype(t.y), typename T::coord_t>;
|
||||
};
|
||||
|
||||
|
||||
// /* SLEW PARAMETERS */
|
||||
|
||||
@ -420,14 +460,85 @@ concept mcc_guiding_model_c = requires(T t) {
|
||||
|
||||
/* MOUNT PROHIBITED ZONE */
|
||||
|
||||
|
||||
struct MccPzoneAbstractInterface {
|
||||
bool inZone(this auto&& self, mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::inZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).inZone(telemetry_data);
|
||||
}
|
||||
}
|
||||
|
||||
bool inZone(this auto&& self, mcc_celestial_point_c auto const& sky_point)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::inZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).inZone(sky_point);
|
||||
}
|
||||
}
|
||||
|
||||
// returns a time to reach the zone
|
||||
auto timeTo(this auto&& self, mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::timeTo method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).timeTo(telemetry_data);
|
||||
}
|
||||
}
|
||||
|
||||
auto timeTo(this auto&& self, mcc_celestial_point_c auto const& sky_point)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::timeTo method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).timeTo(sky_point);
|
||||
}
|
||||
}
|
||||
|
||||
// returns a time to exit from the zone
|
||||
auto timeFrom(this auto&& self, mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::timeFrom method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).timeFrom(telemetry_data);
|
||||
}
|
||||
}
|
||||
|
||||
auto timeFrom(this auto&& self, mcc_celestial_point_c auto const& sky_point)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPzoneAbstractInterface>) {
|
||||
static_assert(false, "Call an empty MccPzoneAbstractInterface::timeFrom method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).timeFrom(sky_point);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename TelemetryDataT>
|
||||
concept mcc_prohibited_zone_c =
|
||||
mcc_mount_telemetry_data_c<TelemetryDataT> && std::movable<T> && requires(T t, const T t_const) {
|
||||
// typename T::coord_t;
|
||||
typename T::coord_t;
|
||||
// typename T::time_point_t;
|
||||
requires mcc_time_duration_c<typename T::duration_t>;
|
||||
|
||||
// static constexpr member to represent inifite duration
|
||||
// static constexpr member to represent infinite duration
|
||||
requires requires {
|
||||
requires std::same_as<decltype(T::infiniteDuration), typename T::duration_t const>;
|
||||
[]() {
|
||||
@ -446,46 +557,11 @@ concept mcc_prohibited_zone_c =
|
||||
};
|
||||
|
||||
|
||||
// the type 'T' must define a static constexpr member of type MccCoordPairKind
|
||||
// to declarate type of coordinate pair used to describe the zone.
|
||||
// This coordinate pair must be used as input in the 'inZone' class method.
|
||||
// requires requires {
|
||||
// requires std::same_as<decltype(T::zoneCoordPairKind), const MccCoordPairKind>;
|
||||
// []() {
|
||||
// constexpr MccCoordPairKind val = T::zoneCoordPairKind;
|
||||
// return val;
|
||||
// }(); // to ensure that 'zoneCoordPairKind' can be used at compile-time context
|
||||
// };
|
||||
|
||||
// return a name of the zone
|
||||
{ t_const.name() } -> mcc_formattable;
|
||||
|
||||
|
||||
// check if given coordinates are into the zone.
|
||||
// input coordinates interpretation is in according to 'zoneCoordPairKind' static constexpr member
|
||||
// {
|
||||
// t.inZone(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>())
|
||||
// } -> std::convertible_to<bool>;
|
||||
|
||||
|
||||
// // for given coordinates and time the method computes a time to reach the zone.
|
||||
// // implementation of the method must assume that input coordinates are apparent RA and DEC at given time
|
||||
// // point, while the time point is one from which computation should be performed (e.g. current time moment)
|
||||
// {
|
||||
// t.timeTo(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
|
||||
// std::declval<typename T::time_point_t>())
|
||||
// } -> mcc_time_duration_c;
|
||||
|
||||
|
||||
// // for given coordinates and time the method computes a time to exit from the zone
|
||||
// {
|
||||
// t.timeFrom(std::declval<typename T::coord_t>(), std::declval<typename T::coord_t>(),
|
||||
// std::declval<typename T::time_point_t>())
|
||||
// } -> mcc_time_duration_c;
|
||||
|
||||
// requires for the methods above with the first argument of type
|
||||
// 'const mcc_mount_telemetry_data_c&' (const lvalue reference)
|
||||
|
||||
{ t.inZone(std::declval<const TelemetryDataT&>()) } -> std::convertible_to<bool>;
|
||||
|
||||
// a time duration to reach the zone.
|
||||
@ -500,12 +576,129 @@ concept mcc_prohibited_zone_c =
|
||||
{ t.timeFrom(std::declval<const TelemetryDataT&>()) } -> std::same_as<typename T::duration_t>;
|
||||
};
|
||||
|
||||
// an input range of prohibited zones
|
||||
template <typename T, typename TelemetryDataT>
|
||||
concept mcc_irange_of_pzones_c = mcc_mount_telemetry_data_c<TelemetryDataT> && std::ranges::input_range<T> &&
|
||||
mcc_prohibited_zone_c<std::ranges::range_value_t<T>, TelemetryDataT>;
|
||||
// // an input range of prohibited zones
|
||||
// template <typename T, typename TelemetryDataT>
|
||||
// concept mcc_irange_of_pzones_c = mcc_mount_telemetry_data_c<TelemetryDataT> && std::ranges::input_range<T> &&
|
||||
// mcc_prohibited_zone_c<std::ranges::range_value_t<T>, TelemetryDataT>;
|
||||
|
||||
|
||||
// // a concept for a callable with the first argument of type satisfied to 'mcc_prohibited_zone_c'
|
||||
// template <typename T, typename TelemetryDataT>
|
||||
// concept mcc_pzone_foreach_func_c = mcc_is_callable<T> && mcc_mount_telemetry_data_c<TelemetryDataT> &&
|
||||
// mcc_prohibited_zone_c<mcc_func_arg1_t<T>, TelemetryDataT>;
|
||||
|
||||
|
||||
// There is no way to declare a concept of class with templated method so one needs to define
|
||||
// a generic interface of prohibited zones holder/container explicitly
|
||||
template <mcc_mount_telemetry_data_c TelemetryDataT>
|
||||
struct MccPZoneAbstractContainer {
|
||||
virtual ~MccPZoneAbstractContainer() = default;
|
||||
|
||||
// must return a size of the container after the addition of the given zone
|
||||
template <mcc_prohibited_zone_c<TelemetryDataT> ZT>
|
||||
size_t pzAddZone(this auto&& self, ZT zone)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzAddZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzAddZone(std::move(zone));
|
||||
}
|
||||
}
|
||||
|
||||
// clear the container
|
||||
auto pzClearZones(this auto&& self)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzClearZones method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzClearZones();
|
||||
}
|
||||
}
|
||||
|
||||
// must return the size of the container (number of zones)
|
||||
size_t pzSize(this auto&& self)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzSize method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// must return true if the given telemetry coordinates are in any of zones in the containe and
|
||||
// false otherwise
|
||||
template <typename RT>
|
||||
bool pzInZone(this auto&& self, const TelemetryDataT& tdata, RT& result)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzInZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzInZone(tdata, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RT>
|
||||
auto pzTimeTo(this auto&& self, const TelemetryDataT& tdata, RT& result)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzInZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzTimeTo(tdata, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RT>
|
||||
auto pzTimeFrom(this auto&& self, const TelemetryDataT& tdata, RT& result)
|
||||
{
|
||||
using self_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<self_t>, MccPZoneAbstractContainer>) {
|
||||
static_assert(false, "Call an empty MccPZoneAbstractContainer::pzInZone method");
|
||||
} else {
|
||||
return std::forward<self_t>(self).pzTimeFrom(tdata, result);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
MccPZoneAbstractContainer() = default;
|
||||
};
|
||||
|
||||
// a full concept for prohibited zones container
|
||||
template <typename T, typename TelemetryDataT>
|
||||
concept mcc_mount_pzones_container_c = std::derived_from<T, MccPZoneAbstractContainer<TelemetryDataT>> && requires {
|
||||
// common time duration type for zones 'timeTo' and 'timeFrom' methods
|
||||
requires mcc_time_duration_c<typename T::duration_t>;
|
||||
|
||||
// static constexpr member to represent infinite duration
|
||||
requires requires {
|
||||
requires std::same_as<decltype(T::infiniteDuration), typename T::duration_t const>;
|
||||
[]() {
|
||||
constexpr auto val = T::infiniteDuration;
|
||||
return val;
|
||||
};
|
||||
};
|
||||
|
||||
// static constexpr member to represent zero duration
|
||||
requires requires {
|
||||
requires std::same_as<decltype(T::zeroDuration), typename T::duration_t const>;
|
||||
[]() {
|
||||
constexpr auto val = T::zeroDuration;
|
||||
return val;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* MOUNT GENERIC CONTROLS */
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ template <MccAltLimitKind KIND = MccAltLimitKind::MIN_ALT_LIMIT>
|
||||
class MccAltLimitPZ
|
||||
// class MccAltLimitPZ : public MccProhibitedZone
|
||||
{
|
||||
protected:
|
||||
static constexpr auto pi2 = std::numbers::pi * 2.0;
|
||||
|
||||
public:
|
||||
@ -36,16 +37,16 @@ public:
|
||||
|
||||
static constexpr MccAltLimitKind altLimitKind = KIND;
|
||||
|
||||
typedef MccAngle coord_t;
|
||||
// floating-point time duration (seconds)
|
||||
typedef std::chrono::duration<double> duration_t;
|
||||
|
||||
typedef MccAngle coord_t;
|
||||
typedef std::chrono::system_clock::time_point time_point_t;
|
||||
|
||||
static constexpr duration_t infiniteDuration{std::numeric_limits<double>::infinity()};
|
||||
static constexpr duration_t zeroDuration{0.0};
|
||||
|
||||
MccAltLimitPZ(const MccAngle& alt_limit, const MccAngle& lat)
|
||||
MccAltLimitPZ(const coord_t& alt_limit, const coord_t& lat, traits::mcc_astrom_engine_c auto* astrom_engine)
|
||||
// : MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE"
|
||||
// : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
|
||||
// : "ALTLIMIT-UNKNOWN"),
|
||||
@ -53,6 +54,21 @@ public:
|
||||
{
|
||||
_lat_lim = pi2 - _abs_lat;
|
||||
_altLimit.normalize<MccAngle::NORM_KIND_90_90>();
|
||||
|
||||
using astrom_engine_t = decltype(*astrom_engine);
|
||||
using astrom_coord_t = typename astrom_engine_t::coord_t;
|
||||
|
||||
static_assert(std::convertible_to<coord_t, astrom_coord_t>,
|
||||
"ASTROMETRY ENGINE AND THE ZONE COORDINATE TYPE ARE NOT COMPATIBLE!");
|
||||
static_assert(std::convertible_to<astrom_coord_t, coord_t>,
|
||||
"ASTROMETRY ENGINE AND THE ZONE COORDINATE TYPE ARE NOT COMPATIBLE!");
|
||||
|
||||
_coord2coord = [astrom_engine, this](MccCoordPairKind kind_from, coord_t x_from, coord_t y_from,
|
||||
time_point_t tpoint, MccCoordPairKind kind_to, coord_t& x_to,
|
||||
coord_t& y_to) {
|
||||
auto err = astrom_engine->coord2coord(kind_from, std::move(x_from), std::move(y_from), tpoint, kind_to,
|
||||
x_to, y_to, tpoint);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -118,59 +134,84 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
|
||||
// bool inZone(const XT& x, const YT& y, traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
|
||||
bool inZone(const XT& x, const YT& y)
|
||||
bool inZone(traits::mcc_celestial_point_c auto const& target)
|
||||
{
|
||||
static constexpr MccCoordPairKind coord_kind = traits::mcc_type_pair_hash<XT, YT>();
|
||||
coord_t alt, az;
|
||||
|
||||
if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_AZALT) { // trivial case
|
||||
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
|
||||
return y <= _altLimit;
|
||||
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) {
|
||||
return y >= _altLimit;
|
||||
}
|
||||
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_AZZD) { // trivial case
|
||||
// return inZone(x, MccAngleALT(std::numbers::pi / 2 - (double)y), utc);
|
||||
return inZone(x, MccAngleALT(std::numbers::pi / 2 - (double)y));
|
||||
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
|
||||
// implementation ...
|
||||
return false;
|
||||
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_RADEC_APP) {
|
||||
// implementation ...
|
||||
return false;
|
||||
} else {
|
||||
throw std::system_error(std::make_error_code(std::errc::operation_not_supported));
|
||||
_coord2coord(target.coordPairKind, target.x, target.y, target.time_point, MccCoordPairKind::COORDS_KIND_AZALT,
|
||||
az, alt);
|
||||
|
||||
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
|
||||
return alt <= _altLimit;
|
||||
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) {
|
||||
return alt >= _altLimit;
|
||||
}
|
||||
}
|
||||
|
||||
duration_t timeTo(traits::mcc_celestial_point_c auto const& target)
|
||||
{
|
||||
coord_t ha, dec;
|
||||
|
||||
if (inZone(target)) {
|
||||
return zeroDuration;
|
||||
}
|
||||
|
||||
return false;
|
||||
_coord2coord(target.coordPairKind, target.x, target.y, target.time_point,
|
||||
MccCoordPairKind::COORDS_KIND_HADEC_APP, ha, dec);
|
||||
|
||||
if (!doesObjectReachZone(ha)) {
|
||||
return infiniteDuration;
|
||||
}
|
||||
|
||||
if constexpr (KIND ==
|
||||
MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one after upper culmination
|
||||
return compute(ha, dec, false);
|
||||
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one before upper
|
||||
// culmination
|
||||
return compute(ha, dec, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
|
||||
duration_t timeTo(const XT& x,
|
||||
const YT& y,
|
||||
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
|
||||
duration_t timeFrom(traits::mcc_celestial_point_c auto const& target)
|
||||
{
|
||||
return duration_t{std::numeric_limits<double>::infinity()};
|
||||
coord_t ha, dec;
|
||||
|
||||
if (!inZone(target)) {
|
||||
return zeroDuration;
|
||||
}
|
||||
|
||||
_coord2coord(target.coordPairKind, target.x, target.y, target.time_point,
|
||||
MccCoordPairKind::COORDS_KIND_HADEC_APP, ha, dec);
|
||||
|
||||
if (!doesObjectExitFromZone(ha)) {
|
||||
return infiniteDuration;
|
||||
}
|
||||
|
||||
if (!doesObjectReachZone(ha)) {
|
||||
return zeroDuration;
|
||||
}
|
||||
|
||||
if constexpr (KIND ==
|
||||
MccAltLimitKind::MIN_ALT_LIMIT) { // the closest time point is one before upper culmination
|
||||
return compute(ha, dec, true);
|
||||
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) { // the closest time point is one after upper
|
||||
// culmination
|
||||
return compute(ha, dec, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
|
||||
duration_t timeFrom(const XT& x,
|
||||
const YT& y,
|
||||
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
|
||||
{
|
||||
return duration_t{0.0};
|
||||
}
|
||||
|
||||
private:
|
||||
MccAngle _altLimit, _latitude, _abs_lat, _lat_lim;
|
||||
coord_t _altLimit, _latitude, _abs_lat, _lat_lim;
|
||||
|
||||
bool doesObjectReachZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
// wrapper function
|
||||
std::function<coord_t(MccCoordPairKind, coord_t, coord_t, time_point_t, MccCoordPairKind, coord_t&, coord_t&)>
|
||||
_coord2coord{};
|
||||
|
||||
bool doesObjectReachZone(const coord_t& dec_app)
|
||||
{
|
||||
// check for limit conditions
|
||||
auto dd = std::abs(telemetry_data.mntDEC);
|
||||
auto dd = std::abs(dec_app);
|
||||
|
||||
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
|
||||
dd += _altLimit;
|
||||
@ -189,11 +230,16 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool doesObjectReachZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
{
|
||||
return doesObjectReachZone(telemetry_data.mntDEC);
|
||||
}
|
||||
|
||||
bool doesObjectExitFromZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
|
||||
bool doesObjectExitFromZone(const coord_t& dec_app)
|
||||
{
|
||||
// check for limit conditions
|
||||
auto dd = std::abs(telemetry_data.mntDEC);
|
||||
auto dd = std::abs(dec_app);
|
||||
|
||||
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
|
||||
dd -= _altLimit;
|
||||
@ -212,10 +258,16 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
duration_t compute(traits::mcc_mount_telemetry_data_c auto const& telemetry_data, bool before_upper_culm)
|
||||
bool doesObjectExitFromZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
|
||||
{
|
||||
double cos_ha = (std::sin(_altLimit) - std::sin(telemetry_data.mntDEC) * std::sin(_latitude)) /
|
||||
std::cos(telemetry_data.mntDEC) / std::cos(_latitude);
|
||||
return doesObjectExitFromZone(telemetry_data.mntDEC);
|
||||
}
|
||||
|
||||
|
||||
duration_t compute(const coord_t& ha_app, const coord_t& dec_app, bool before_upper_culm)
|
||||
{
|
||||
double cos_ha =
|
||||
(std::sin(_altLimit) - std::sin(dec_app) * std::sin(_latitude)) / std::cos(dec_app) / std::cos(_latitude);
|
||||
|
||||
if (cos_ha > 1.0) { // should not be!
|
||||
return infiniteDuration;
|
||||
@ -228,7 +280,7 @@ private:
|
||||
ha = std::acos(cos_ha); // HA after upper culmination!!
|
||||
}
|
||||
|
||||
MccAngle time_ang = ha - telemetry_data.mntHA; // in sideral time scale
|
||||
MccAngle time_ang = ha - ha_app; // in sideral time scale
|
||||
|
||||
if (time_ang < 0.0) { // next day
|
||||
time_ang += pi2;
|
||||
@ -238,6 +290,11 @@ private:
|
||||
|
||||
return duration_t{time_ang.seconds()};
|
||||
}
|
||||
|
||||
duration_t compute(traits::mcc_mount_telemetry_data_c auto const& telemetry_data, bool before_upper_culm)
|
||||
{
|
||||
return compute(telemetry_data.mntHA, telemetry_data.mntDEC, before_upper_culm);
|
||||
}
|
||||
};
|
||||
|
||||
typedef MccAltLimitPZ<MccAltLimitKind::MIN_ALT_LIMIT> MccMinAltPZ;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
||||
|
||||
|
||||
/* AN DEFAULT IMPLEMENTATION OF PROHIBITED ZONES HOLDER */
|
||||
/* A DEFAULT IMPLEMENTATION OF PROHIBITED ZONES HOLDER */
|
||||
|
||||
#include "mcc_mount_concepts.h"
|
||||
|
||||
@ -11,7 +11,7 @@ namespace mcc
|
||||
{
|
||||
|
||||
template <traits::mcc_mount_telemetry_data_c TelemetryDataT>
|
||||
class MccPZoneHolder
|
||||
class MccPZoneContainer : public traits::MccPZoneAbstractContainer<TelemetryDataT>
|
||||
{
|
||||
public:
|
||||
typedef TelemetryDataT telemetry_data_t;
|
||||
@ -21,7 +21,7 @@ public:
|
||||
|
||||
// adaptor class for prohibited zones
|
||||
struct MccPZoneWrapper {
|
||||
using duration_t = MccPZoneHolder::duration_t;
|
||||
using duration_t = MccPZoneContainer::duration_t;
|
||||
|
||||
static constexpr duration_t infiniteDuration{std::numeric_limits<double>::infinity()};
|
||||
static constexpr duration_t zeroDuration{0.0};
|
||||
@ -53,7 +53,11 @@ public:
|
||||
MccPZoneWrapper() = default;
|
||||
};
|
||||
|
||||
size_t pzNumberOfZones() const { return _pzWrapperVec.size(); }
|
||||
MccPZoneContainer() = default;
|
||||
virtual ~MccPZoneContainer() = default;
|
||||
|
||||
|
||||
size_t pzSize() const { return _pzWrapperVec.size(); }
|
||||
|
||||
// add zone/zones
|
||||
template <traits::mcc_prohibited_zone_c<telemetry_data_t> ZT,
|
||||
@ -156,10 +160,108 @@ public:
|
||||
return in_zone;
|
||||
}
|
||||
|
||||
template <std::ranges::output_range<bool> RT>
|
||||
bool pzInZone(traits::mcc_celestial_point_c auto const& target, RT& result)
|
||||
{
|
||||
bool in_zone = false;
|
||||
|
||||
auto const p_target = ⌖
|
||||
|
||||
result = pzForeachZone<RT>([&in_zone, p_target](auto& wr) {
|
||||
bool r = wr.inZone(*p_target);
|
||||
in_zone |= r;
|
||||
|
||||
return r;
|
||||
});
|
||||
|
||||
return in_zone;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<MccPZoneWrapper> _pzWrapperVec{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PZC
|
||||
{
|
||||
protected:
|
||||
struct point_t {
|
||||
typedef std::chrono::system_clock::time_point time_point_t;
|
||||
typedef double coord_t;
|
||||
|
||||
time_point_t time_point;
|
||||
MccCoordPairKind coordPairKind;
|
||||
coord_t x, y;
|
||||
};
|
||||
|
||||
static_assert(traits::mcc_celestial_point_c<point_t>);
|
||||
|
||||
template <typename ZT>
|
||||
static inline std::unordered_map<const PZC*, std::vector<std::shared_ptr<ZT>>> _zones{};
|
||||
|
||||
std::vector<std::function<void()>> _clearFunc{};
|
||||
|
||||
// template <typename ZT, typename CPT>
|
||||
// static inline std::unordered_map<const PZC*, std::function<std::vector<bool>(const CPT&)>> _inZoneFunc = [](){
|
||||
|
||||
// };
|
||||
// template <typename ZT, typename CPT>
|
||||
// static inline std::function<std::vector<bool>(const PZC*, const CPT&)> _inZoneFunc =
|
||||
// [](const PZC* cont, const CPT& cp) {
|
||||
// std::vector<bool> res;
|
||||
|
||||
// for (ZT& zone : _zones<ZT>[cont]) {
|
||||
// res.emplace_back(zone.inZone(cp));
|
||||
// }
|
||||
|
||||
// return res;
|
||||
// };
|
||||
|
||||
std::vector<std::function<bool(const point_t&)>> _inZoneFunc;
|
||||
|
||||
public:
|
||||
template <typename ZT>
|
||||
size_t addZone(ZT zone)
|
||||
{
|
||||
auto sptr = std::make_shared<ZT>(std::move(zone));
|
||||
|
||||
_zones<ZT>[this].emplace_back(sptr);
|
||||
|
||||
if (_zones<ZT>[this].size() == 1) {
|
||||
_clearFunc.emplace_back([this]() { _zones<ZT>[this].clear(); });
|
||||
|
||||
_inZoneFunc.emplace_back([sptr](const point_t& cp) { return sptr->inZone(cp); });
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CPT, std::ranges::output_range<bool> RT>
|
||||
bool inZone(const CPT& cp, RT& res)
|
||||
{
|
||||
using tp_t = typename point_t::time_point_t;
|
||||
using cp_tp_t = typename CPT::time_point_t;
|
||||
|
||||
bool in_zone = false, r;
|
||||
|
||||
point_t pt{.coordPairKind = cp.coordPairKind, .x = cp.x, .y = cp.y};
|
||||
if constexpr (traits::mcc_systime_c<cp_tp_t>) {
|
||||
pt.time_point = std::chrono::time_point_cast<tp_t>(cp.time_point);
|
||||
} else if constexpr (std::is_arithmetic_v<cp_tp_t>) {
|
||||
pt.time_point = tp_t{std::chrono::duration<tp_t::rep>(static_cast<tp_t::rep>(cp.time_point))};
|
||||
} else {
|
||||
static_assert(false, "INVALID TYPE!");
|
||||
}
|
||||
|
||||
res = RT();
|
||||
for (auto& func : _inZoneFunc) {
|
||||
r = func(pt);
|
||||
in_zone |= r;
|
||||
|
||||
std::back_inserter(res) = r;
|
||||
}
|
||||
|
||||
return in_zone;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc
|
||||
@ -143,7 +143,7 @@ public:
|
||||
typename ASTROM_ENGINE_T::coord_t xdiff, ydiff, r2;
|
||||
};
|
||||
|
||||
MccMountTelemetry(astrom_engine_t& astrom_engine, pec_t& pec, hardware_t& hardware)
|
||||
MccMountTelemetry(astrom_engine_t* astrom_engine, pec_t* pec, hardware_t* hardware)
|
||||
: base_t(astrom_engine, pec), _hardware(hardware)
|
||||
{
|
||||
}
|
||||
@ -221,7 +221,7 @@ public:
|
||||
|
||||
typename hardware_t::axes_pos_t ax_pos;
|
||||
|
||||
auto err = _hardware.getPos(ax_pos);
|
||||
auto err = _hardware->getPos(ax_pos);
|
||||
if (err) {
|
||||
if constexpr (std::same_as<error_t, decltype(err)>) {
|
||||
return err;
|
||||
@ -357,7 +357,7 @@ public:
|
||||
|
||||
protected:
|
||||
mount_telemetry_data_t _data{};
|
||||
hardware_t& _hardware;
|
||||
hardware_t* _hardware;
|
||||
|
||||
std::unique_ptr<std::mutex> _updateMutex;
|
||||
std::unique_ptr<std::condition_variable> _updateCondVar;
|
||||
|
||||
@ -104,7 +104,7 @@ public:
|
||||
|
||||
typedef std::error_code error_t;
|
||||
|
||||
MccMountTelemetryAstromTransform(astrom_engine_t& astrom_engine, pec_t& pec)
|
||||
MccMountTelemetryAstromTransform(astrom_engine_t* astrom_engine, pec_t* pec)
|
||||
: _astromEngine(astrom_engine), _pec(pec)
|
||||
{
|
||||
}
|
||||
@ -166,9 +166,9 @@ public:
|
||||
typename pec_t::error_t pec_err;
|
||||
|
||||
auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) {
|
||||
auto ast_err = _astromEngine.greg2jul(time_point, jd);
|
||||
auto ast_err = _astromEngine->greg2jul(time_point, jd);
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine.apparentSiderTime(jd, lst, true);
|
||||
ast_err = _astromEngine->apparentSiderTime(jd, lst, true);
|
||||
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine->eqOrigins(jd, eo);
|
||||
@ -180,7 +180,7 @@ public:
|
||||
|
||||
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
||||
typename pec_t::pec_result_t pec_res;
|
||||
pec_err = _pec.compute(coord.x, coord.y, pec_res);
|
||||
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
||||
if (!pec_err) {
|
||||
X_app = coord.x + pec_res.dx;
|
||||
Y_app = coord.y + pec_res.dy;
|
||||
@ -202,7 +202,7 @@ public:
|
||||
Y_app = coord.y;
|
||||
XX_app = HA;
|
||||
} else if constexpr (altAzMount) {
|
||||
ast_err = _astromEngine.hadec2azalt(HA, coord.y, X_app, Y_app);
|
||||
ast_err = _astromEngine->hadec2azalt(HA, coord.y, X_app, Y_app);
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
||||
}
|
||||
@ -217,15 +217,15 @@ public:
|
||||
Y_app = coord.y;
|
||||
XX_app = lst - coord.x + eo;
|
||||
} else if constexpr (altAzMount) {
|
||||
ast_err = _astromEngine.hadec2azalt(coord.x, coord.y, X_app, Y_app);
|
||||
ast_err = _astromEngine->hadec2azalt(coord.x, coord.y, X_app, Y_app);
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED MOUNT TYPE!");
|
||||
}
|
||||
}
|
||||
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
||||
if constexpr (equatorialMount) {
|
||||
ast_err = _astromEngine.azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC
|
||||
if (!ast_err) { // compute CIO RA (as XX_app)
|
||||
ast_err = _astromEngine->azalt2hadec(coord.x, coord.y, X_app, Y_app); // compute HA-DEC
|
||||
if (!ast_err) { // compute CIO RA (as XX_app)
|
||||
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
||||
coord.x = X_app;
|
||||
coord.y = Y_app;
|
||||
@ -250,9 +250,9 @@ public:
|
||||
// for alt-azimuthal mount:
|
||||
// X_app = AZ, Y_app = ALT
|
||||
|
||||
ast_err = _astromEngine.greg2jul(time_point, jd);
|
||||
ast_err = _astromEngine->greg2jul(time_point, jd);
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine.icrs2obs(coord.x, coord.y, jd, X_app, Y_app, XX_app, az, alt, eo);
|
||||
ast_err = _astromEngine->icrs2obs(coord.x, coord.y, jd, X_app, Y_app, XX_app, az, alt, eo);
|
||||
|
||||
if (!ast_err) {
|
||||
if constexpr (equatorialMount) {
|
||||
@ -297,7 +297,7 @@ public:
|
||||
|
||||
if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_XY) { // from encoder's
|
||||
typename pec_t::pec_result_t pec_res;
|
||||
pec_err = _pec.compute(coord.x, coord.y, pec_res);
|
||||
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
||||
if (!pec_err) {
|
||||
coord.x += pec_res.dx;
|
||||
coord.y += pec_res.dy;
|
||||
@ -332,9 +332,9 @@ public:
|
||||
if (coord.coordPairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
typename astrom_engine_t::jd_t jd;
|
||||
|
||||
ast_err = _astromEngine.greg2jul(astrom_engine_t::timePointNow(), jd);
|
||||
ast_err = _astromEngine->greg2jul(astrom_engine_t::timePointNow(), jd);
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine.obs2icrs(coord.coordPairKind, coord.x, coord.y, jd, RA, DEC);
|
||||
ast_err = _astromEngine->obs2icrs(coord.coordPairKind, coord.x, coord.y, jd, RA, DEC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,9 +371,9 @@ public:
|
||||
sideral_time_t lst;
|
||||
|
||||
auto get_jd_lst_eo = [&time_point, this](jd_t& jd, sideral_time_t& lst, eo_t& eo) {
|
||||
auto ast_err = _astromEngine.greg2jul(time_point, jd);
|
||||
auto ast_err = _astromEngine->greg2jul(time_point, jd);
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine.apparentSiderTime(jd, lst, true);
|
||||
ast_err = _astromEngine->apparentSiderTime(jd, lst, true);
|
||||
|
||||
if (!ast_err) {
|
||||
ast_err = _astromEngine->eqOrigins(jd, eo);
|
||||
@ -404,7 +404,7 @@ public:
|
||||
if constexpr (equatorialMount) {
|
||||
typename pec_t::pec_result_t pec_res;
|
||||
|
||||
pec_err = _pec.compute(coord.x, coord.y, pec_res);
|
||||
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
||||
if (!pec_err) {
|
||||
X = coord.x - pec_res.dx;
|
||||
Y = coord.y - pec_res.dy;
|
||||
@ -413,7 +413,7 @@ public:
|
||||
}
|
||||
} else if constexpr (altAzMount) {
|
||||
coord_t az, alt;
|
||||
ast_err = _astromEngine.hadec2azalt(coord.x, coord.y, az, alt);
|
||||
ast_err = _astromEngine->hadec2azalt(coord.x, coord.y, az, alt);
|
||||
if (!ast_err) {
|
||||
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT;
|
||||
coord.x = az;
|
||||
@ -427,7 +427,7 @@ public:
|
||||
} else if (coord.coordPairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // from app AZ-ALT
|
||||
if constexpr (equatorialMount) {
|
||||
coord_t ha, dec;
|
||||
ast_err = _astromEngine.azalt2hadec(coord.x, coord.y, ha, dec);
|
||||
ast_err = _astromEngine->azalt2hadec(coord.x, coord.y, ha, dec);
|
||||
if (!ast_err) {
|
||||
coord.coordPairKind == MccCoordPairKind::COORDS_KIND_HADEC_APP;
|
||||
coord.x = ha;
|
||||
@ -438,7 +438,7 @@ public:
|
||||
} else if constexpr (altAzMount) {
|
||||
typename pec_t::pec_result_t pec_res;
|
||||
|
||||
pec_err = _pec.compute(coord.x, coord.y, pec_res);
|
||||
pec_err = _pec->compute(coord.x, coord.y, pec_res);
|
||||
if (!pec_err) {
|
||||
X = coord.x - pec_res.dx;
|
||||
Y = coord.y - pec_res.dy;
|
||||
@ -456,7 +456,7 @@ public:
|
||||
coord_t ra, dec, ha, az, alt;
|
||||
eo_t eo;
|
||||
|
||||
ast_err = _astromEngine.greg2jul(time_point, jd);
|
||||
ast_err = _astromEngine->greg2jul(time_point, jd);
|
||||
if (!ast_err) {
|
||||
ast_err = icrs2obs(coord.x, coord.y, jd, ra, dec, ha, az, alt, eo);
|
||||
if (!ast_err) {
|
||||
@ -499,8 +499,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
astrom_engine_t& _astromEngine;
|
||||
pec_t& _pec;
|
||||
astrom_engine_t* _astromEngine;
|
||||
pec_t* _pec;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ namespace mcc
|
||||
|
||||
struct MccCelestialPoint {
|
||||
typedef double coord_t;
|
||||
typedef std::chrono::system_clock::time_point time_point_t;
|
||||
|
||||
MccCoordPairKind coordPairKind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
coord_t x{0.0}, y{0.0};
|
||||
|
||||
@ -129,9 +129,9 @@ public:
|
||||
traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T,
|
||||
// traits::mcc_tuple_c PZ_T, // std::tuple of prohibited zones
|
||||
typename... LoggerCtorArgTs>
|
||||
MccSimpleSlewModel(TELEMETRY_T& telemetry,
|
||||
HARDWARE_T& hardware,
|
||||
PZ_T& prohibited_zone,
|
||||
MccSimpleSlewModel(TELEMETRY_T* telemetry,
|
||||
HARDWARE_T* hardware,
|
||||
PZ_T* prohibited_zone,
|
||||
LoggerCtorArgTs&&... ctor_args)
|
||||
requires(!std::same_as<LoggerT, MccNullLogger>)
|
||||
: LoggerT(std::forward<LoggerCtorArgTs>(ctor_args)...)
|
||||
@ -141,16 +141,16 @@ public:
|
||||
init(telemetry, hardware, prohibited_zone);
|
||||
}
|
||||
|
||||
template <traits::mcc_mount_telemetry_c TELEMETRY_T,
|
||||
traits::mcc_mount_hardware_c HARDWARE_T,
|
||||
traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T
|
||||
// traits::mcc_tuple_c PZ_T // std::tuple of prohibited zones
|
||||
>
|
||||
MccSimpleSlewModel(TELEMETRY_T& telemetry, HARDWARE_T& hardware, PZ_T& prohibited_zone)
|
||||
requires(std::same_as<LoggerT, MccNullLogger>)
|
||||
{
|
||||
init(telemetry, hardware, prohibited_zone);
|
||||
}
|
||||
// template <traits::mcc_mount_telemetry_c TELEMETRY_T,
|
||||
// traits::mcc_mount_hardware_c HARDWARE_T,
|
||||
// traits::mcc_irange_of_pzones_c<typename TELEMETRY_T::mount_telemetry_data_t> PZ_T
|
||||
// // traits::mcc_tuple_c PZ_T // std::tuple of prohibited zones
|
||||
// >
|
||||
// MccSimpleSlewModel(TELEMETRY_T& telemetry, HARDWARE_T& hardware, PZ_T& prohibited_zone)
|
||||
// requires(std::same_as<LoggerT, MccNullLogger>)
|
||||
// {
|
||||
// init(telemetry, hardware, prohibited_zone);
|
||||
// }
|
||||
|
||||
MccSimpleSlewModel(MccSimpleSlewModel&& other)
|
||||
: _stopRequested(other._stopRequested.load()), _slewFunc(std::move(other._slewFunc))
|
||||
@ -195,21 +195,21 @@ protected:
|
||||
std::atomic_bool _stopRequested{false};
|
||||
std::function<error_t(const slew_point_t&)> _slewFunc{};
|
||||
|
||||
void init(auto& telemetry, auto& hardware, auto& prohibited_zones)
|
||||
void init(auto* p_telemetry, auto* p_hardware, auto* p_prohibited_zones)
|
||||
{
|
||||
// deduce controls types
|
||||
using hardware_t = decltype(hardware);
|
||||
using telemetry_t = decltype(telemetry);
|
||||
using hardware_t = decltype(*p_hardware);
|
||||
using telemetry_t = decltype(*p_telemetry);
|
||||
static_assert(traits::mcc_mount_default_telemetry_c<telemetry_t>,
|
||||
"TELEMETRY CLASS MUST BE A DESCENDANT OF 'MccMountTelemetry'!");
|
||||
|
||||
using astrom_engine_t = typename telemetry_t::astrom_engine_t;
|
||||
|
||||
static constexpr size_t Nzones = std::tuple_size_v<decltype(prohibited_zones)>;
|
||||
static constexpr size_t Nzones = std::tuple_size_v<decltype(*p_prohibited_zones)>;
|
||||
|
||||
const auto p_telemetry = &telemetry;
|
||||
const auto p_hardware = &hardware;
|
||||
const auto p_prohibited_zones = &prohibited_zones;
|
||||
// const auto p_telemetry = &telemetry;
|
||||
// const auto p_hardware = &hardware;
|
||||
// const auto p_prohibited_zones = &prohibited_zones;
|
||||
|
||||
_slewFunc = [p_telemetry, p_hardware, p_prohibited_zones, this](slew_point_t slew_point) {
|
||||
_stopRequested = false;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user