This commit is contained in:
Timur A. Fatkhullin 2025-06-14 15:29:01 +03:00
parent 3a28c3299f
commit 4c8e3f4caf
3 changed files with 462 additions and 8 deletions

372
cxx/mcc_mount_coord.h Normal file
View File

@ -0,0 +1,372 @@
#pragma once
#include "mcc_traits.h"
#include "utils.h"
constexpr double operator""_rads(long double val) // angle in radians (no conversion)
{
return val;
}
constexpr double operator""_degs(long double val) // angle in degrees
{
return val * std::numbers::pi / 180.0;
}
constexpr double operator""_dms(const char* s, size_t size) // as a string "DEGREES:MINUTES:SECONDS"
{
auto res = mcc::utils::parsAngleString(std::span{s, size});
if (res.has_value()) {
return res.value() * std::numbers::pi / 180.0;
} else {
throw std::invalid_argument("invalid sexagesimal representation");
}
}
constexpr double operator""_hms(const char* s, size_t len) // as a string "HOURS:MINUTES:SECONDS"
{
auto res = mcc::utils::parsAngleString(std::span{s, len}, true);
if (res.has_value()) {
return res.value() * std::numbers::pi / 180.0;
} else {
throw std::invalid_argument("invalid sexagesimal representation");
}
}
namespace mcc
{
/* MCC-LIBRARY COORDINATES REPRESENTATION DEFINITIONS AND CLASS */
// tags for MccAngle class construction
struct MccRadianTag {
};
struct MccDegreeTag {
};
static constexpr MccDegreeTag mcc_degrees{};
struct MccHMSTag {
};
static constexpr MccHMSTag mcc_hms{};
class MccAngle
{
protected:
double _angleInRads{0.0};
int _precision{2};
public:
enum norm_kind_t {
NORM_KIND_0_360, // [0,360]
NORM_KIND_0_180, // [0,180]
NORM_KIND_180_180, // [-180,180]
NORM_KIND_90_90, // [-90,90]
};
MccAngle() = default;
// by default angle is in radians
MccAngle(std::convertible_to<double> auto const& val, const MccRadianTag = MccRadianTag{}) : _angleInRads(val) {}
// construct angle in degrees, e.g.:
// auto ang = MccAngle{180.0, mcc_degrees};
MccAngle(std::convertible_to<double> auto const& val, const MccDegreeTag)
{
_angleInRads = val * utils::deg2radCoeff;
}
// constuct angle from sexagesimal representation or floating-point number of degrees, e.g.:
// auto ang = MccAngle{"-12:34:56.789"}; // from degrees:minutes:seconds
// auto ang = MccAngle{"123.574698"}; // from degrees
MccAngle(traits::mcc_input_char_range auto const& val)
{
auto res = utils::parsAngleString(val);
if (res.has_value()) {
_angleInRads = res.value() * utils::deg2radCoeff;
} else {
throw std::invalid_argument("invalid sexagesimal representation");
}
}
// construct angle from sexagesimal representation or floating-point number of degrees, e.g.:
// auto ang = MccAngle{"01:23:45.6789", mcc_hms}; // from hours:minutes:seconds
// auto ang = MccAngle{"123.574698"}; // from degrees
MccAngle(traits::mcc_input_char_range auto const& val, const MccHMSTag)
{
auto res = utils::parsAngleString(val, true);
if (res.has_value()) {
_angleInRads = res.value() * utils::deg2radCoeff;
} else {
throw std::invalid_argument("invalid sexagesimal representation");
}
}
virtual ~MccAngle() = default;
// normalize coordinate
template <norm_kind_t KIND>
MccAngle& normalize()
{
_angleInRads = std::fmod(_angleInRads, std::numbers::pi * 2.0);
if constexpr (KIND == NORM_KIND_0_360) {
if (_angleInRads < 0.0) {
_angleInRads += 2.0 * std::numbers::pi;
}
} else if constexpr (KIND == NORM_KIND_0_180) {
if (_angleInRads < -std::numbers::pi) {
_angleInRads = 2.0 * std::numbers::pi + _angleInRads;
} else if (_angleInRads < 0.0) {
_angleInRads = -_angleInRads;
}
} else if constexpr (KIND == NORM_KIND_180_180) {
if (_angleInRads > std::numbers::pi) {
_angleInRads = 2.0 * std::numbers::pi - _angleInRads;
} else if (_angleInRads < -std::numbers::pi) {
_angleInRads += 2.0 * std::numbers::pi;
}
} else if constexpr (KIND == NORM_KIND_90_90) {
if (_angleInRads >= 1.5 * std::numbers::pi) {
_angleInRads = _angleInRads - 2.0 * std::numbers::pi;
} else if (_angleInRads >= std::numbers::pi / 2.0) {
_angleInRads = std::numbers::pi - _angleInRads;
} else if (_angleInRads <= -1.5 * std::numbers::pi) {
_angleInRads += 2.0 * std::numbers::pi;
} else if (_angleInRads <= -std::numbers::pi / 2.0) {
_angleInRads = -(std::numbers::pi + _angleInRads);
}
}
return *this;
}
MccAngle& normalize()
{
return normalize<NORM_KIND_0_360>();
}
template <typename T>
operator T() const
requires std::is_arithmetic_v<T>
{
return _angleInRads;
}
operator double() const
{
return _angleInRads;
}
template <typename T>
T degrees() const
{
return _angleInRads * 180.0 / std::numbers::pi;
}
double degrees() const
{
return degrees<double>();
}
template <traits::mcc_output_char_range T>
T sexagesimal(bool hms, int prec = 2) const
{
return utils::rad2sxg(_angleInRads, hms, prec >= 0 ? prec : _precision);
}
std::string sexagesimal(bool hms, int prec = 2) const
{
return sexagesimal<std::string>(hms, prec);
}
// arithmetics
template <typename SelfT, std::convertible_to<MccAngle> T>
SelfT& operator+=(this SelfT& self, const T& v)
{
if constexpr (std::derived_from<T, MccAngle>) {
static_assert(std::derived_from<SelfT, T>, "INCOMPATIBLE TYPES!");
self._angleInRads += v._angleInRads;
} else if constexpr (std::is_arithmetic_v<T>) {
self._angleInRads += v;
} else {
self._angleInRads += MccAngle(v)._angleInRads;
}
return self;
}
template <typename SelfT, std::convertible_to<MccAngle> T>
SelfT& operator-=(this SelfT& self, const T& v)
{
if constexpr (std::derived_from<T, MccAngle>) {
static_assert(std::derived_from<SelfT, T>, "INCOMPATIBLE TYPES!");
self._angleInRads -= v._angleInRads;
} else if constexpr (std::is_arithmetic_v<T>) {
self._angleInRads -= v;
} else {
self._angleInRads -= MccAngle(v)._angleInRads;
}
return self;
}
template <typename SelfT, typename T>
SelfT& operator*=(this SelfT& self, const T& v)
requires std::is_arithmetic_v<T>
{
self._angleInRads *= v;
return self;
}
template <typename SelfT, typename T>
SelfT& operator/=(this SelfT& self, const T& v)
requires std::is_arithmetic_v<T>
{
self._angleInRads /= v;
return self;
}
template <typename SelfT>
SelfT& operator-(this SelfT& self)
{
self._angleInRads = -self._angleInRads;
return self;
}
};
// binary arithmetic operations
template <std::convertible_to<MccAngle> T1, std::convertible_to<MccAngle> T2>
auto operator+(const T1& v1, const T2& v2)
{
static_assert(std::convertible_to<T1, T2> || std::convertible_to<T2, T1>, "INCOMPATIBLE TYPES!");
using res_t = std::conditional_t<std::convertible_to<T1, T2>, T1, T2>;
return res_t{(double)v1 + (double)v2};
}
template <std::convertible_to<MccAngle> T1, std::convertible_to<MccAngle> T2>
auto operator-(const T1& v1, const T2& v2)
{
static_assert(std::convertible_to<T1, T2> || std::convertible_to<T2, T1>, "INCOMPATIBLE TYPES!");
using res_t = std::conditional_t<std::convertible_to<T1, T2>, T1, T2>;
return res_t{(double)v1 - (double)v2};
}
template <std::convertible_to<MccAngle> T1, std::convertible_to<MccAngle> T2>
auto operator*(const T1& v1, const T2& v2)
{
if constexpr (std::is_arithmetic_v<T1>) {
return v2 *= v1;
} else if constexpr (std::is_arithmetic_v<T2>) {
return v1 *= v2;
} else {
static_assert(false, "INCOMPATIBLE TYPES!");
}
}
template <std::convertible_to<MccAngle> T1, typename T2>
auto operator/(const T1& v1, const T2& v2)
requires std::is_arithmetic_v<T2>
{
return v1 /= v2;
}
/* */
class MccAngleRA_ICRS : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleDEC_ICRS : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleRA_APP : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleDEC_APP : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleHA : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleAZ : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleZD : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleALT : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleX : public MccAngle // some co-longitude coordinate
{
using MccAngle::MccAngle;
};
class MccAngleY : public MccAngle // some co-latitude coordinate
{
using MccAngle::MccAngle;
};
class MccAngleLAT : public MccAngle
{
using MccAngle::MccAngle;
};
class MccAngleLON : public MccAngle
{
using MccAngle::MccAngle;
};
enum class MccCoordPairKind : size_t {
COORDS_KIND_GENERIC = traits::mcc_type_pair_hash<MccAngle, MccAngle>(),
COORDS_KIND_RADEC_ICRS = traits::mcc_type_pair_hash<MccAngleRA_ICRS, MccAngleDEC_ICRS>(),
COORDS_KIND_RADEC_APP = traits::mcc_type_pair_hash<MccAngleRA_APP, MccAngleDEC_APP>(),
COORDS_KIND_HADEC = traits::mcc_type_pair_hash<MccAngleHA, MccAngleDEC_APP>(),
COORDS_KIND_AZZD = traits::mcc_type_pair_hash<MccAngleAZ, MccAngleZD>(),
COORDS_KIND_AZALT = traits::mcc_type_pair_hash<MccAngleAZ, MccAngleALT>(),
COORDS_KIND_XY = traits::mcc_type_pair_hash<MccAngleX, MccAngleY>(),
COORDS_KIND_LATLON = traits::mcc_type_pair_hash<MccAngleLAT, MccAngleLON>()
};
} // namespace mcc

View File

@ -7,7 +7,7 @@
#include <chrono>
#include <string_view>
#include "mcc_coord.h"
#include "mcc_mount_coord.h"
#include "mcc_traits.h"
namespace mcc
@ -20,9 +20,9 @@ public:
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; // a time duration to reach the zone
pz_duration_t time_from; // a time duration to exit the zone
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
};
struct pz_context_t {
@ -35,19 +35,60 @@ public:
return _name;
}
bool inZone(const MccAngle& x,
const MccAngle& y,
// check if given position (x,y) in the zone
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
bool inZone(const XT& x,
const YT& y,
const pz_context_t& context,
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
{
static constexpr size_t coord_kind = traits::mcc_type_pair_hash<XT, YT>();
return false;
}
pz_request_t request(const MccAngle& x,
const MccAngle& y,
// 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& x,
const YT& y,
const pz_context_t& context,
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
{
static constexpr size_t coord_kind = traits::mcc_type_pair_hash<XT, YT>();
}
// 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& x,
const YT& y,
const pz_context_t& context,
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
{
static constexpr size_t coord_kind = traits::mcc_type_pair_hash<XT, YT>();
}
template <std::derived_from<MccAngle> XT, std::derived_from<MccAngle> YT>
pz_request_t request(const XT& x,
const YT& y,
const pz_context_t& context,
traits::mcc_systime_c auto const& utc = std::chrono::system_clock::now())
{
pz_request_t res{.in_zone = false, .time_to = pz_duration_t{0.0}, .time_from{0.0}};
res.in_zone = inZone(x, y, context, utc);
if (res.in_zone) {
res.time_from = timeFrom(x, y, context, utc);
} else {
res.time_to = timeFrom(x, y, context, utc);
}
return res;
}
protected:

View File

@ -131,4 +131,45 @@ template <typename T>
using mcc_func_arg1_t = typename mcc_func_traits<T>::arg1_t;
namespace details
{
// compile-time hash for type
// (from https://stackoverflow.com/questions/56292104/hashing-types-at-compile-time-in-c17-c2a)
// WARNING: it does not work for unnamed struct!!!
template <typename T>
static consteval size_t Hash()
{
size_t result{};
#ifdef _MSC_VER
for (const auto& c : __FUNCSIG__)
#else // GCC and clang
for (const auto& c : __PRETTY_FUNCTION__)
#endif
(result ^= c) <<= 1;
return result;
}
} // namespace details
template <typename T>
static constexpr size_t mcc_type_hash = details::Hash<T>();
static constexpr size_t mcc_hash_combine(size_t lhs, size_t rhs)
{
constexpr size_t v_const = sizeof(size_t) >= 8 ? 0x517cc1b727220a95 : 0x9e3779b9;
lhs ^= rhs + v_const + (lhs << 6) + (lhs >> 2);
return lhs;
}
template <typename T1, typename T2>
static constexpr size_t mcc_type_pair_hash()
{
return mcc_hash_combine(mcc_type_hash<T1>, mcc_type_hash<T2>);
}
} // namespace mcc::traits