mountcontrol/cxx/mcc_coord.h
2025-04-16 18:12:02 +03:00

194 lines
5.0 KiB
C++

#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 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<double> 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<double> auto const& val, const MccDegreeTag tag)
{
_angleInRads = val * utils::deg2radCoeff;
}
// constuct angle from sexagesimal representation or floating-point number of degrees, e.g.:
// auto ang = MccCoordinate{"-12:34:56.789"}; // from degrees:minutes:seconds
// auto ang = MccCoordinate{"123.574698"}; // from degrees
MccCoordinate(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 = MccCoordinate{"01:23:45.6789", mcc_hms}; // from hours:minutes:seconds
// auto ang = MccCoordinate{"123.574698"}; // from degrees
MccCoordinate(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");
}
}
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);
}
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 <typename T>
MccCoordinate operator*(T&& scalar)
requires std::is_arithmetic_v<std::remove_cvref_t<T>>
{
return _angleInRads * scalar;
}
template <typename T>
MccCoordinate operator/(T&& scalar)
requires std::is_arithmetic_v<std::remove_cvref_t<T>>
{
return _angleInRads / scalar;
}
template <typename T>
MccCoordinate operator-() // unary '-'
requires std::is_arithmetic_v<std::remove_cvref_t<T>>
{
return -_angleInRads;
}
MccCoordinate& operator+=(const MccCoordinate& v)
{
_angleInRads += v._angleInRads;
return *this;
}
MccCoordinate& operator-=(const MccCoordinate& v)
{
_angleInRads += v._angleInRads;
return *this;
}
template <typename T>
MccCoordinate& operator*=(T&& scalar)
requires std::is_arithmetic_v<std::remove_cvref_t<T>>
{
_angleInRads *= scalar;
return *this;
}
template <typename T>
MccCoordinate& operator/=(T&& scalar)
requires std::is_arithmetic_v<std::remove_cvref_t<T>>
{
_angleInRads /= scalar;
return *this;
}
};
} // namespace mcc