This commit is contained in:
Timur A. Fatkhullin 2025-06-15 13:15:32 +03:00
parent a43b6587b6
commit 98d5fa007f
4 changed files with 132 additions and 44 deletions

View File

@ -154,4 +154,17 @@ if (WITH_TESTS)
set(FSM_TEST_APP fsm_test) set(FSM_TEST_APP fsm_test)
add_executable(${FSM_TEST_APP} tests/fsm_test.cpp) add_executable(${FSM_TEST_APP} tests/fsm_test.cpp)
# set(TESTS_SRC tests/configfile_test.cpp tests/astrom_test.cpp tests/fitpack_test.cpp tests/fsm_test.cpp)
set(TESTS_SRC tests/coord.cpp)
create_test_sourcelist(Tests common_tests.cpp ${TESTS_SRC})
add_executable(common_tests ${Tests})
# target_include_directories(common_tests PRIVATE ${FITPACK_INCLUDE_DIR})
foreach (test ${TESTS_SRC})
get_filename_component (TName ${test} NAME_WE)
add_test (NAME ${TName} COMMAND common_tests tests/${TName})
endforeach ()
enable_testing()
endif() endif()

View File

@ -70,15 +70,34 @@ public:
MccAngle() = default; MccAngle() = default;
// by default angle is in radians // by default angle is in radians
MccAngle(std::convertible_to<double> auto const& val, const MccRadianTag = MccRadianTag{}) : _angleInRads(val) {} // MccAngle(std::convertible_to<double> auto const& val, const MccRadianTag = MccRadianTag{}) : _angleInRads(val) {}
// construct angle in degrees, e.g.: // construct angle in degrees, e.g.:
// auto ang = MccAngle{180.0, mcc_degrees}; // auto ang = MccAngle{180.0, mcc_degrees};
MccAngle(std::convertible_to<double> auto const& val, const MccDegreeTag) // MccAngle(std::convertible_to<double> auto const& val, const MccDegreeTag)
// {
// _angleInRads = val * utils::deg2radCoeff;
// }
// by default angle is in radians
template <typename T>
MccAngle(const T& val, const MccRadianTag = MccRadianTag{})
requires std::is_arithmetic_v<T>
: _angleInRads(val)
{ {
_angleInRads = val * utils::deg2radCoeff;
} }
// construct angle in degrees, e.g.:
// auto ang = MccAngle{180.0, mcc_degrees};
template <typename T>
MccAngle(const T& val, const MccDegreeTag)
requires std::is_arithmetic_v<T>
: _angleInRads(val * utils::deg2radCoeff)
{
}
// constuct angle from sexagesimal representation or floating-point number of degrees, e.g.: // 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{"-12:34:56.789"}; // from degrees:minutes:seconds
// auto ang = MccAngle{"123.574698"}; // from degrees // auto ang = MccAngle{"123.574698"}; // from degrees
@ -144,23 +163,17 @@ public:
return *this; return *this;
} }
MccAngle& normalize() MccAngle& normalize() { return normalize<NORM_KIND_0_360>(); }
{
return normalize<NORM_KIND_0_360>();
}
template <typename T> // template <typename T>
operator T() const // operator T() const
requires std::is_arithmetic_v<T> // requires std::is_arithmetic_v<T>
{ // {
return _angleInRads; // return _angleInRads;
} // }
operator double() const operator double() const { return _angleInRads; }
{
return _angleInRads;
}
template <typename T> template <typename T>
@ -169,21 +182,15 @@ public:
return _angleInRads * 180.0 / std::numbers::pi; return _angleInRads * 180.0 / std::numbers::pi;
} }
double degrees() const double degrees() const { return degrees<double>(); }
{
return degrees<double>();
}
template <traits::mcc_output_char_range T> template <traits::mcc_output_char_range T>
T sexagesimal(bool hms, int prec = 2) const T sexagesimal(bool hms = false, int prec = 2) const
{ {
return utils::rad2sxg(_angleInRads, hms, prec >= 0 ? prec : _precision); return utils::rad2sxg(_angleInRads, hms, prec >= 0 ? prec : _precision);
} }
std::string sexagesimal(bool hms, int prec = 2) const std::string sexagesimal(bool hms = false, int prec = 2) const { return sexagesimal<std::string>(hms, prec); }
{
return sexagesimal<std::string>(hms, prec);
}
// arithmetics // arithmetics
@ -256,7 +263,7 @@ auto operator+(const T1& v1, const T2& v2)
{ {
static_assert(std::convertible_to<T1, T2> || std::convertible_to<T2, T1>, "INCOMPATIBLE TYPES!"); 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>; using res_t = std::conditional_t<std::convertible_to<T1, T2> && std::derived_from<T1, MccAngle>, T1, T2>;
return res_t{(double)v1 + (double)v2}; return res_t{(double)v1 + (double)v2};
} }
@ -266,7 +273,7 @@ auto operator-(const T1& v1, const T2& v2)
{ {
static_assert(std::convertible_to<T1, T2> || std::convertible_to<T2, T1>, "INCOMPATIBLE TYPES!"); 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>; using res_t = std::conditional_t<std::convertible_to<T1, T2> && std::derived_from<T1, MccAngle>, T1, T2>;
return res_t{(double)v1 - (double)v2}; return res_t{(double)v1 - (double)v2};
} }
@ -324,23 +331,18 @@ class MccAngleAZ : public MccAngle
using MccAngle::MccAngle; using MccAngle::MccAngle;
}; };
class MccAngleALT; struct MccAngleALT; // just forward declaration
class MccAngleZD : public MccAngle struct MccAngleZD : public MccAngle {
{
using MccAngle::MccAngle; using MccAngle::MccAngle;
MccAngleZD(const MccAngleALT&); MccAngleZD(const MccAngleALT&);
}; };
class MccAngleALT : public MccAngle struct MccAngleALT : public MccAngle {
{
using MccAngle::MccAngle; using MccAngle::MccAngle;
MccAngleALT(const MccAngleZD& zd) MccAngleALT(const MccAngleZD& zd) { _angleInRads = std::numbers::pi / 2.0 - (double)zd; }
{
_angleInRads = std::numbers::pi / 2.0 - (double)zd;
}
}; };

57
cxx/tests/coord.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <iostream>
#include "../mcc_mount_coord.h"
struct Q {
};
int tests_coord(int argc, char* argv[])
{
using namespace mcc;
std::cout << "\n\n\n------- mcc_mount_coords.h -------\n";
MccAngle ang("90:30:00"_dms);
std::cout << "ang_degs = " << ang.degrees() << "\n";
std::cout << "ang_rads = " << (float)ang << "\n";
MccAngleALT alt(30.0_degs);
MccAngleZD zd(alt);
std::cout << "alt = " << alt.degrees() << "\n";
std::cout << "zd (from alt) = " << zd.degrees() << "\n";
std::cout << "\n";
MccAngleRA_APP ra(10.0_degs);
MccAngleDEC_APP dec(20.0_degs);
ang = 45.500_degs;
auto rr = ra + ang;
std::cout << "ra (" << ra.degrees() << "_degs) = " << ra.sexagesimal(true) << " in HH::MM::SS.SS\n";
std::cout << "ang (" << ang.degrees() << "_degs) = " << ang.sexagesimal(true) << " in HH::MM::SS.SS\n";
std::cout << "rr = ra + ang = " << rr.sexagesimal(true) << "\n";
auto r = 1.1 + ra;
std::cout << "r = ra + 1.1 = " << r.sexagesimal(true) << "\n";
std::cout << "(int)ra = " << (int)ra << " in radians\n";
MccAngleY y{123.457};
// should not compiled
// auto r1 = ra + y;
auto yy = y - 243.234;
std::cout << "yy = " << yy.degrees() << "\n";
yy.normalize<mcc::MccAngle::NORM_KIND_0_360>();
std::cout << "yy_norm = " << yy.degrees() << "\n";
std::cout << "(unsigned long)yy_norm = " << static_cast<unsigned long>(yy) << " in radians\n";
std::cout << "std::cos(yy_norm) = " << std::cos(yy) << "\n";
MccAngle ha(MccAngle{0.111});
return 0;
}

View File

@ -14,6 +14,13 @@ namespace mcc::utils
static const std::regex decimalNumberRx{" *[-+]?([0-9]*[.])?[0-9]+([eE][-+]?[0-9]+)? *"}; static const std::regex decimalNumberRx{" *[-+]?([0-9]*[.])?[0-9]+([eE][-+]?[0-9]+)? *"};
static const std::regex sexagesimalReprRx{" *[-+]?[0-9]{1,2}:[0-9]{1,2}:([0-9]{0,2}[.])?[0-9]+ *"}; static const std::regex sexagesimalReprRx{" *[-+]?[0-9]{1,2}:[0-9]{1,2}:([0-9]{0,2}[.])?[0-9]+ *"};
static bool isEqual(std::floating_point auto const& v1, std::floating_point auto const& v2)
{
constexpr auto eps = std::numeric_limits<std::common_type_t<decltype(v1), decltype(v2)>>::epsilon();
return std::fabs(v1 - v2) <= eps * std::fmax(std::fabs(v1), std::fabs(v2));
}
enum class TrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH }; enum class TrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH };
template <std::ranges::contiguous_range R> template <std::ranges::contiguous_range R>
@ -224,10 +231,26 @@ static R rad2sxg(double ang, bool hms = false, int prec = 2)
degs /= 15.0; degs /= 15.0;
} }
auto term = 10.0;
for (int i = 1; i < prec; ++i) {
term *= 10.0;
}
auto d = std::trunc(degs); auto d = std::trunc(degs);
auto s = (degs - d) * 60.0; auto s = (degs - d) * 60.0;
auto m = std::trunc(s); auto m = std::trunc(s);
s = (s - m) * 60.0; s = (s - m) * 60.0;
// round to given precision
s = std::round(s * term) / term;
if (isEqual(s, 60.0)) {
m += 1.0;
s = 0.0;
if (isEqual(m, 60.0)) {
d += 1.0;
m = 0.0;
}
}
if (ang < 0) { if (ang < 0) {
std::ranges::copy(std::string_view("-"), std::back_inserter(res)); std::ranges::copy(std::string_view("-"), std::back_inserter(res));
@ -285,11 +308,4 @@ static std::string AZZD_rad2sxg(double az, double zd, std::string_view delim = "
} }
static bool isEqual(std::floating_point auto const& v1, std::floating_point auto const& v2)
{
constexpr auto eps = std::numeric_limits<std::common_type_t<decltype(v1), decltype(v2)>>::epsilon();
return std::fabs(v1 - v2) <= eps * std::fmax(std::fabs(v1), std::fabs(v2));
}
} // namespace mcc::utils } // namespace mcc::utils