305 lines
8.9 KiB
C++
305 lines
8.9 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
|
|
{
|
|
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_90_90, // [-90,90]
|
|
};
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
virtual ~MccCoordinate() = default;
|
|
|
|
// normalize coordinate
|
|
template <norm_kind_t KIND>
|
|
MccCoordinate& 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_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;
|
|
}
|
|
|
|
MccCoordinate& normalize()
|
|
{
|
|
return normalize<NORM_KIND_0_360>();
|
|
}
|
|
|
|
|
|
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+(std::convertible_to<MccCoordinate> auto&& left,
|
|
std::convertible_to<MccCoordinate> auto&& right)
|
|
{
|
|
// return std::forward<decltype(left)>(left)._angleInRads +
|
|
// std::forward<decltype(right)>(right)._angleInRads;
|
|
return MccCoordinate{std::forward<decltype(left)>(left)}._angleInRads +
|
|
MccCoordinate{std::forward<decltype(right)>(right)}._angleInRads;
|
|
}
|
|
// friend MccCoordinate operator+(const MccCoordinate& left, const MccCoordinate& right)
|
|
// {
|
|
// return left._angleInRads + right._angleInRads;
|
|
// }
|
|
|
|
|
|
friend MccCoordinate operator-(std::convertible_to<MccCoordinate> auto&& left,
|
|
std::convertible_to<MccCoordinate> auto&& right)
|
|
{
|
|
// return std::forward<decltype(left)>(left)._angleInRads -
|
|
// std::forward<decltype(right)>(right)._angleInRads;
|
|
return MccCoordinate{std::forward<decltype(left)>(left)}._angleInRads -
|
|
MccCoordinate{std::forward<decltype(right)>(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;
|
|
}
|
|
|
|
auto operator<=>(const MccCoordinate& other) const
|
|
{
|
|
return _angleInRads <=> other._angleInRads;
|
|
}
|
|
|
|
auto operator==(const MccCoordinate& other) const
|
|
{
|
|
return _angleInRads == other._angleInRads;
|
|
}
|
|
|
|
auto operator<=>(double other) const
|
|
{
|
|
return _angleInRads <=> other;
|
|
}
|
|
|
|
auto operator==(double other) const
|
|
{
|
|
return _angleInRads == other;
|
|
}
|
|
};
|
|
|
|
enum class MccNormCoordKind {
|
|
NORM_KIND_0_360, // [0,360]
|
|
NORM_KIND_0_180, // [0,180]
|
|
NORM_KIND_90_90, // [-90,90]
|
|
};
|
|
|
|
template <MccNormCoordKind KIND = MccNormCoordKind::NORM_KIND_0_360>
|
|
class MccNormCoordinate : public MccCoordinate
|
|
{
|
|
public:
|
|
static constexpr MccNormCoordKind normKind = KIND;
|
|
|
|
protected:
|
|
static constexpr double pi2 = 2.0 * std::numbers::pi;
|
|
static constexpr double normScale = KIND == MccNormCoordKind::NORM_KIND_0_360 ? std::numbers::pi * 2.0
|
|
: KIND == MccNormCoordKind::NORM_KIND_0_180 ? std::numbers::pi
|
|
: std::numbers::pi / 2.0;
|
|
|
|
void norm()
|
|
{
|
|
_angleInRads = std::fmod(_angleInRads, normScale);
|
|
if constexpr (KIND == MccNormCoordKind::NORM_KIND_0_360) {
|
|
_angleInRads += normScale;
|
|
} else if constexpr (KIND == MccNormCoordKind::NORM_KIND_0_180) {
|
|
_angleInRads = -_angleInRads;
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace mcc
|