diff --git a/cxx/CMakeLists.txt b/cxx/CMakeLists.txt index d9df2dd..3e9a2ba 100644 --- a/cxx/CMakeLists.txt +++ b/cxx/CMakeLists.txt @@ -154,4 +154,17 @@ if (WITH_TESTS) set(FSM_TEST_APP fsm_test) 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() diff --git a/cxx/mcc_mount_coord.h b/cxx/mcc_mount_coord.h index 8fb353a..4bf296d 100644 --- a/cxx/mcc_mount_coord.h +++ b/cxx/mcc_mount_coord.h @@ -70,15 +70,34 @@ public: MccAngle() = default; // by default angle is in radians - MccAngle(std::convertible_to auto const& val, const MccRadianTag = MccRadianTag{}) : _angleInRads(val) {} + // MccAngle(std::convertible_to 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 auto const& val, const MccDegreeTag) + // MccAngle(std::convertible_to auto const& val, const MccDegreeTag) + // { + // _angleInRads = val * utils::deg2radCoeff; + // } + + // by default angle is in radians + template + MccAngle(const T& val, const MccRadianTag = MccRadianTag{}) + requires std::is_arithmetic_v + : _angleInRads(val) { - _angleInRads = val * utils::deg2radCoeff; } + // construct angle in degrees, e.g.: + // auto ang = MccAngle{180.0, mcc_degrees}; + template + MccAngle(const T& val, const MccDegreeTag) + requires std::is_arithmetic_v + : _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 @@ -144,23 +163,17 @@ public: return *this; } - MccAngle& normalize() - { - return normalize(); - } + MccAngle& normalize() { return normalize(); } - template - operator T() const - requires std::is_arithmetic_v - { - return _angleInRads; - } + // template + // operator T() const + // requires std::is_arithmetic_v + // { + // return _angleInRads; + // } - operator double() const - { - return _angleInRads; - } + operator double() const { return _angleInRads; } template @@ -169,21 +182,15 @@ public: return _angleInRads * 180.0 / std::numbers::pi; } - double degrees() const - { - return degrees(); - } + double degrees() const { return degrees(); } template - 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); } - std::string sexagesimal(bool hms, int prec = 2) const - { - return sexagesimal(hms, prec); - } + std::string sexagesimal(bool hms = false, int prec = 2) const { return sexagesimal(hms, prec); } // arithmetics @@ -256,7 +263,7 @@ auto operator+(const T1& v1, const T2& v2) { static_assert(std::convertible_to || std::convertible_to, "INCOMPATIBLE TYPES!"); - using res_t = std::conditional_t, T1, T2>; + using res_t = std::conditional_t && std::derived_from, T1, T2>; return res_t{(double)v1 + (double)v2}; } @@ -266,7 +273,7 @@ auto operator-(const T1& v1, const T2& v2) { static_assert(std::convertible_to || std::convertible_to, "INCOMPATIBLE TYPES!"); - using res_t = std::conditional_t, T1, T2>; + using res_t = std::conditional_t && std::derived_from, T1, T2>; return res_t{(double)v1 - (double)v2}; } @@ -324,23 +331,18 @@ class MccAngleAZ : public MccAngle using MccAngle::MccAngle; }; -class MccAngleALT; +struct MccAngleALT; // just forward declaration -class MccAngleZD : public MccAngle -{ +struct MccAngleZD : public MccAngle { using MccAngle::MccAngle; MccAngleZD(const MccAngleALT&); }; -class MccAngleALT : public MccAngle -{ +struct MccAngleALT : public MccAngle { using MccAngle::MccAngle; - MccAngleALT(const MccAngleZD& zd) - { - _angleInRads = std::numbers::pi / 2.0 - (double)zd; - } + MccAngleALT(const MccAngleZD& zd) { _angleInRads = std::numbers::pi / 2.0 - (double)zd; } }; diff --git a/cxx/tests/coord.cpp b/cxx/tests/coord.cpp new file mode 100644 index 0000000..cb75bd1 --- /dev/null +++ b/cxx/tests/coord.cpp @@ -0,0 +1,57 @@ +#include + +#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(); + std::cout << "yy_norm = " << yy.degrees() << "\n"; + std::cout << "(unsigned long)yy_norm = " << static_cast(yy) << " in radians\n"; + + std::cout << "std::cos(yy_norm) = " << std::cos(yy) << "\n"; + + MccAngle ha(MccAngle{0.111}); + + return 0; +} diff --git a/cxx/utils.h b/cxx/utils.h index d97131e..e112824 100644 --- a/cxx/utils.h +++ b/cxx/utils.h @@ -14,6 +14,13 @@ namespace mcc::utils 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 bool isEqual(std::floating_point auto const& v1, std::floating_point auto const& v2) +{ + constexpr auto eps = std::numeric_limits>::epsilon(); + + return std::fabs(v1 - v2) <= eps * std::fmax(std::fabs(v1), std::fabs(v2)); +} + enum class TrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH }; template @@ -224,10 +231,26 @@ static R rad2sxg(double ang, bool hms = false, int prec = 2) degs /= 15.0; } + auto term = 10.0; + for (int i = 1; i < prec; ++i) { + term *= 10.0; + } + auto d = std::trunc(degs); auto s = (degs - d) * 60.0; auto m = std::trunc(s); + 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) { 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>::epsilon(); - - return std::fabs(v1 - v2) <= eps * std::fmax(std::fabs(v1), std::fabs(v2)); -} - } // namespace mcc::utils