#pragma once #include "mcc_traits.h" #include "utils.h" namespace mcc { /* MCC-LIBRARY COORDINATES REPRESENTATION DEFINITIONS AND CLASS */ 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 = 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 size) // as a string "HOURS:MINUTES:SECONDS" { auto res = utils::parsAngleString(std::span{s, size}, true); if (res.has_value()) { return res.value() * std::numbers::pi / 180.0; } else { throw std::invalid_argument("invalid sexagesimal representation"); } } // tags for MccCoordinate class construction struct MccRadianTag { }; struct MccDegreeTag { }; static constexpr MccDegreeTag mcc_degrees{}; struct MccHMSTag { }; static constexpr MccHMSTag mcc_hms{}; // coordinate representation class class MccCoordinate { double _angleInRads{0.0}; int _precision{2}; public: MccCoordinate() = default; // by default angle is in radians MccCoordinate(std::convertible_to auto const& val, const MccRadianTag tag = MccRadianTag{}) : _angleInRads(val) { } // construct angle in degrees, e.g.: // auto ang = MccCoordinate{180.0, mcc_degrees}; MccCoordinate(std::convertible_to auto const& val, const MccDegreeTag tag) { _angleInRads = val * std::numbers::pi / 180.0; } // constuct angle from sexagesimal representation, e.g.: // auto ang = MccCoordinate{"-12:34:56.789"}; // from degrees:minutes:seconds MccCoordinate(traits::mcc_input_char_range auto const& val) { auto res = utils::parsAngleString(val); if (res.has_value()) { _angleInRads = res.value() * std::numbers::pi / 180.0; } else { throw std::invalid_argument("invalid sexagesimal representation"); } } // construct angle from sexagesimal representation, e.g.: // auto ang = MccCoordinate{"01:23:45.6789", mcc_hms}; // from hours:minutes:seconds MccCoordinate(traits::mcc_input_char_range auto const& val, const MccHMSTag) { auto res = utils::parsAngleString(val, true); if (res.has_value()) { _angleInRads = res.value() * std::numbers::pi / 180.0; } else { throw std::invalid_argument("invalid sexagesimal representation"); } } operator double() const { return _angleInRads; } template T degrees() const { return _angleInRads * 180.0 / std::numbers::pi; } double degrees() const { return degrees(); } template 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(hms, prec); } friend MccCoordinate operator+(const MccCoordinate& left, const MccCoordinate& right) { return left._angleInRads + right._angleInRads; } friend MccCoordinate operator-(const MccCoordinate& left, const MccCoordinate& right) { return left._angleInRads + right._angleInRads; } template MccCoordinate operator*(T&& scalar) requires std::is_arithmetic_v> { return _angleInRads * scalar; } template MccCoordinate operator/(T&& scalar) requires std::is_arithmetic_v> { return _angleInRads / scalar; } template MccCoordinate operator-() // unary '-' requires std::is_arithmetic_v> { return -_angleInRads; } MccCoordinate& operator+=(const MccCoordinate& v) { _angleInRads += v._angleInRads; return *this; } MccCoordinate& operator-=(const MccCoordinate& v) { _angleInRads += v._angleInRads; return *this; } template MccCoordinate& operator*=(T&& scalar) requires std::is_arithmetic_v> { _angleInRads *= scalar; return *this; } template MccCoordinate& operator/=(T&& scalar) requires std::is_arithmetic_v> { _angleInRads /= scalar; return *this; } }; } // namespace mcc