This commit is contained in:
2025-07-15 17:32:48 +03:00
parent 62258a991b
commit 46e4b1e95f
8 changed files with 383 additions and 226 deletions

View File

@@ -7,93 +7,18 @@
#include <chrono>
#include <string_view>
#include "mcc_mount_concepts.h"
#include "mcc_mount_coord.h"
#include "mcc_traits.h"
namespace mcc
{
class MccProhibitedZone
{
public:
static constexpr MccCoordPairKind preferedCoordKind = MccCoordPairKind::COORDS_KIND_AZALT;
static constexpr double mcc_UT1_to_sideral_ratio = 1.002737909350795; // UT1/sideral
// floating-point time duration (seconds)
typedef std::chrono::duration<double> pz_duration_t;
struct pz_request_t {
bool in_zone{false}; // true if given coordinates are within the zone
pz_duration_t time_to{0.0}; // a time duration to reach the zone
pz_duration_t time_from{0.0}; // a time duration to exit the zone
};
virtual ~MccProhibitedZone() = default;
std::string_view name() const
{
return _name;
}
// check if given position (x,y) in the zone
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
bool inZone(const XT&, const YT&, traits::mcc_systime_c auto const&)
{
return false;
}
// returns a time duration to reach the zone
// 0 - if already within
// Inf - if it never reaches the zone
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
pz_duration_t timeTo(const XT&, const YT&, traits::mcc_systime_c auto const&)
{
return pz_duration_t{std::numeric_limits<double>::infinity()};
}
// returns a time duration to exit from the zone
// 0 - if given position (x,y) is out of the zone
// Inf - if (x,y) is always within the zone
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
pz_duration_t timeFrom(const XT&, const YT&, traits::mcc_systime_c auto const&)
{
return pz_duration_t{0.0};
}
// all-in-one request (call three methods above)
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
pz_request_t request(this auto&& self,
const XT& x,
const YT& y,
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
{
using self_t = decltype(self);
pz_request_t res{.in_zone = false, .time_to = pz_duration_t{0.0}, .time_from{0.0}};
res.in_zone = std::forward<self_t>(self).inZone(x, y, utc);
if (res.in_zone) {
res.time_from = std::forward<self_t>(self).timeFrom(x, y, utc);
} else {
res.time_to = std::forward<self_t>(self).timeTo(x, y, utc);
}
return res;
}
protected:
MccProhibitedZone(std::string_view name) : _name(name) {}
std::string_view _name;
};
/* SOME PROHIBITED ZONE IMPLEMENTATIONS */
/* SOME SIMPLE PROHIBITED ZONE IMPLEMENTATIONS */
// minimal or maximal altitude prohibited zones
@@ -101,26 +26,86 @@ protected:
enum class MccAltLimitKind { MIN_ALT_LIMIT, MAX_ALT_LIMIT };
template <MccAltLimitKind KIND = MccAltLimitKind::MIN_ALT_LIMIT>
class MccAltLimitPZ : public MccProhibitedZone
class MccAltLimitPZ
// class MccAltLimitPZ : public MccProhibitedZone
{
static constexpr auto pi2 = std::numbers::pi * 2.0;
public:
static constexpr MccCoordPairKind preferedCoordKind = MccCoordPairKind::COORDS_KIND_AZALT;
static constexpr MccAltLimitKind altLimitKind = KIND;
// floating-point time duration (seconds)
typedef std::chrono::duration<double> pz_duration_t;
typedef MccAngle coord_t;
typedef std::chrono::system_clock::time_point time_point_t;
static constexpr pz_duration_t infDuration{std::numeric_limits<double>::infinity()};
static constexpr pz_duration_t zeroDuration{0.0};
//
// TODO: add context (e.g. TT-TAI, UT1-UTC, geo location and so on)!!!
MccAltLimitPZ(const MccAngle& alt_limit)
: MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE"
: KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
: "ALTLIMIT-UNKNOWN"),
_altLimit(alt_limit)
MccAltLimitPZ(const MccAngle& alt_limit, const MccAngle& lat)
// : MccProhibitedZone(KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE"
// : KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
// : "ALTLIMIT-UNKNOWN"),
: _altLimit(alt_limit), _latitude(lat), _abs_lat(std::abs(_latitude)), _lat_lim(pi2 - _abs_lat)
{
_altLimit.normalize<MccAngle::NORM_KIND_90_90>();
}
consteval std::string_view name() const
{
return KIND == MccAltLimitKind::MIN_ALT_LIMIT ? "MINALT-ZONE"
: KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
: "ALTLIMIT-UNKNOWN";
}
// check if current mount coordinates are within the zone
bool inZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
{
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
return telemetry_data.mntALT <= _altLimit;
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) {
return telemetry_data.mntALT >= _altLimit;
}
}
// returns a time to reach the zone
pz_duration_t timeTo(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
{
if (inZone(telemetry_data)) {
return zeroDuration;
}
if (!doesObjectReachZone(telemetry_data)) {
return infDuration;
}
return compute(telemetry_data);
}
// returns a time to exit from the zone
pz_duration_t timeFrom(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
{
if (!inZone(telemetry_data)) {
return zeroDuration;
}
if (!doesObjectReachZone(telemetry_data)) {
return zeroDuration;
}
return compute(telemetry_data);
}
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, traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
bool inZone(const XT& x, const YT& y)
{
static constexpr MccCoordPairKind coord_kind = traits::mcc_type_pair_hash<XT, YT>();
@@ -131,7 +116,8 @@ public:
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), utc);
return inZone(x, MccAngleALT(std::numbers::pi / 2 - (double)y));
} else if constexpr (coord_kind == MccCoordPairKind::COORDS_KIND_HADEC_APP) {
// implementation ...
return false;
@@ -164,8 +150,51 @@ public:
}
private:
MccAngle _altLimit;
MccAngle _altLimit, _latitude, _abs_lat, _lat_lim;
bool doesObjectReachZone(traits::mcc_mount_telemetry_data_c auto const& telemetry_data)
{
// check for limit conditions
auto dd = std::abs(telemetry_data.mntDEC);
if constexpr (KIND == MccAltLimitKind::MIN_ALT_LIMIT) {
dd += _altLimit;
if (dd > _lat_lim) { // never fall below altitude limit
return false;
}
} else if constexpr (KIND == MccAltLimitKind::MAX_ALT_LIMIT) {
if ((dd < (_abs_lat - _altLimit)) || (dd > (_abs_lat + _altLimit))) { // never rise above altitude limit
return false;
}
} else {
static_assert(false, "UNKNOWN ALTITUDE LIMIT TYPE!");
}
return true;
}
pz_duration_t compute(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);
if (cos_ha > 1.0) { // should not be!
return infDuration;
}
MccAngle time_ang = std::acos(cos_ha) - telemetry_data.mntHA; // in sideral time scale
if (time_ang < 0.0) { // next day
time_ang += pi2;
}
time_ang *= mcc_UT1_to_sideral_ratio;
return pz_duration_t{time_ang.seconds()};
}
};
typedef MccAltLimitPZ<MccAltLimitKind::MIN_ALT_LIMIT> MccMinAltPZ;
typedef MccAltLimitPZ<MccAltLimitKind::MAX_ALT_LIMIT> MccMaxAltPZ;
} // namespace mcc