From 5811c12aa1ea5b22f3fc353a6feff953a9d718f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cruz?= Date: Sun, 7 May 2023 01:13:50 -0300 Subject: [PATCH 1/3] Add geometry Angle that wraps floating points in a radian angle class --- robocin/CMakeLists.txt | 1 + robocin/geometry/angle.cpp | 14 ++ robocin/geometry/angle.h | 275 +++++++++++++++++++++ robocin/geometry/internal/angle_internal.h | 18 ++ 4 files changed, 308 insertions(+) create mode 100644 robocin/geometry/angle.cpp create mode 100644 robocin/geometry/angle.h create mode 100644 robocin/geometry/internal/angle_internal.h diff --git a/robocin/CMakeLists.txt b/robocin/CMakeLists.txt index f8474db..b881332 100644 --- a/robocin/CMakeLists.txt +++ b/robocin/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(geometry) add_subdirectory(utility) diff --git a/robocin/geometry/angle.cpp b/robocin/geometry/angle.cpp new file mode 100644 index 0000000..017bd18 --- /dev/null +++ b/robocin/geometry/angle.cpp @@ -0,0 +1,14 @@ +// +// Created by José Cruz on 08/04/23. +// Copyright (c) 2023 RobôCIn. +// + +#include "robocin/geometry/angle.h" + +namespace robocin { + +template class Angle; +template class Angle; +template class Angle; + +} // namespace robocin diff --git a/robocin/geometry/angle.h b/robocin/geometry/angle.h new file mode 100644 index 0000000..125d2b9 --- /dev/null +++ b/robocin/geometry/angle.h @@ -0,0 +1,275 @@ +// +// Created by José Cruz on 08/04/23. +// Copyright (c) 2023 RobôCIn. +// + +#ifndef ROBOCIN_GEOMETRY_ANGLE_H +#define ROBOCIN_GEOMETRY_ANGLE_H + +#include +#include +#include + +#include "robocin/utility/angular.h" +#include "robocin/utility/concepts.h" +#include "robocin/utility/fuzzy_compare.h" +#include "robocin/utility/type_traits.h" + +#include "robocin/geometry/internal/angle_internal.h" + +namespace robocin { + +template +class Angle { + public: + // Member types ---------------------------------------------------------------------------------- + using type = F; + + // Friendships ----------------------------------------------------------------------------------- + template + friend class Angle; + + // Static constructors --------------------------------------------------------------------------- + static constexpr Angle fromDegrees(type degrees) { + return Angle{degrees * kDegreesToRadiansFactor}; + } + + // Constructors ---------------------------------------------------------------------------------- + constexpr Angle() = default; + constexpr Angle(const Angle&) = default; + constexpr Angle(Angle&&) noexcept = default; + + // NOLINTBEGIN(google-explicit-constructor, hicpp-explicit-conversions) + template G> + constexpr Angle(const Angle& other) : value_{static_cast(other)} {} + template G> + constexpr Angle(Angle&& other) noexcept : value_{static_cast(std::move(other))} {} + // NOLINTEND(google-explicit-constructor, hicpp-explicit-conversions) + + constexpr explicit Angle(type radians) : value_{radians} {} + + // Destructor ------------------------------------------------------------------------------------ + constexpr ~Angle() = default; + + // Implicit conversion operator ------------------------------------------------------------------ + // NOLINTBEGIN(google-explicit-constructor, hicpp-explicit-conversions) + constexpr operator type() const { return value_; } + // NOLINTEND(google-explicit-constructor, hicpp-explicit-conversions) + + // Assignment operators -------------------------------------------------------------------------- + // NOLINTBEGIN(cppcoreguidelines-c-copy-assignment-signature) + // NOLINTBEGIN(misc-unconventional-assign-operator) + constexpr Angle& operator=(type radians) { return value_ = radians, *this; } + // NOLINTEND(misc-unconventional-assign-operator) + // NOLINTEND(cppcoreguidelines-c-copy-assignment-signature) + constexpr Angle& operator=(const Angle&) = default; + constexpr Angle& operator=(Angle&&) noexcept = default; + + // Arithmetic-assignment operators --------------------------------------------------------------- + constexpr Angle& operator+=(type scalar) { return value_ += scalar, *this; } + constexpr Angle& operator-=(type scalar) { return value_ -= scalar, *this; } + constexpr Angle& operator*=(type scalar) { return value_ *= scalar, *this; } + constexpr Angle& operator/=(type scalar) { return value_ /= scalar, *this; } + + template + constexpr Angle& operator+=(const Angle& other) { + return value_ += other.value_, *this; + } + template + constexpr Angle& operator-=(const Angle& other) { + return value_ -= other.value_, *this; + } + template + constexpr Angle& operator*=(const Angle& other) { + return value_ *= other.value_, *this; + } + template + constexpr Angle& operator/=(const Angle& other) { + return value_ /= other.value_, *this; + } + + // Arithmetic operators -------------------------------------------------------------------------- + [[nodiscard]] constexpr Angle operator+(type scalar) const { return Angle{value_ + scalar}; } + [[nodiscard]] constexpr Angle operator-(type scalar) const { return Angle{value_ - scalar}; } + [[nodiscard]] constexpr Angle operator*(type scalar) const { return Angle{value_ * scalar}; } + [[nodiscard]] constexpr Angle operator/(type scalar) const { return Angle{value_ / scalar}; } + + template + [[nodiscard]] constexpr Angle operator+(const Angle& other) const { + return Angle{value_ + other.value_}; + } + template + [[nodiscard]] constexpr Angle operator-(const Angle& other) const { + return Angle{value_ - other.value_}; + } + template + [[nodiscard]] constexpr Angle operator*(const Angle& other) const { + return Angle{value_ * other.value_}; + } + template + [[nodiscard]] constexpr Angle operator/(const Angle& other) const { + return Angle{value_ / other.value_}; + } + + // Arithmetic friend operators ------------------------------------------------------------------- + friend constexpr Angle operator*(type scalar, const Angle& angle) { + return Angle{angle * scalar}; + } + + // Sign operators -------------------------------------------------------------------------------- + [[nodiscard]] constexpr Angle operator+() const { return *this; } + [[nodiscard]] constexpr Angle operator-() const { return Angle{-value_}; } + + // Getters --------------------------------------------------------------------------------------- + [[nodiscard]] constexpr type degrees() const { return value_ * kRadiansToDegreesFactor; } + [[nodiscard]] constexpr type radians() const { return value_; } + + // Geometry -------------------------------------------------------------------------------------- + [[nodiscard]] constexpr type sin() const { return std::sin(value_); } + [[nodiscard]] constexpr type cos() const { return std::cos(value_); } + [[nodiscard]] constexpr type tan() const { return std::tan(value_); } + + constexpr void normalize() & { value_ = normalizeAngle(value_); } + [[nodiscard]] constexpr Angle normalized() && { return normalize(), std::move(*this); } + [[nodiscard]] constexpr Angle normalized() const& { return Angle{*this}.normalized(); } + + constexpr void differentiateWith(type other) & { value_ = smallestAngleDiff(value_, other); } + [[nodiscard]] constexpr Angle differentiatedWith(type other) && { + return differentiateWith(other), std::move(*this); + } + [[nodiscard]] constexpr Angle differentiatedWith(type other) const& { + return Angle{*this}.differentiateWith(other); + } + + constexpr void absDifferentiateWith(type other) & { + value_ = std::abs(smallestAngleDiff(value_, other)); + } + [[nodiscard]] constexpr Angle absDifferentiatedWith(type other) && { + return absDifferentiateWith(other), std::move(*this); + } + [[nodiscard]] constexpr Angle absDifferentiatedWith(type other) const& { + return Angle{*this}.absDifferentiateWith(other); + } + + // Validators ------------------------------------------------------------------------------------ + [[nodiscard]] constexpr bool isNull() const { + if constexpr (has_epsilon_v) { + return fuzzyIsZero(value_); + } + return value_ == 0; + } + + // Equality operators ---------------------------------------------------------------------------- + template + [[nodiscard]] constexpr bool operator==(const Angle& other) const { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpEqual(value_, other.value_); + } else { + return value_ == other.value_; + } + } + template + [[nodiscard]] constexpr bool operator==(G scalar) const { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpEqual(value_, scalar); + } else { + return value_ == scalar; + } + } + + // Equality friend operator ---------------------------------------------------------------------- + template + [[nodiscard]] friend constexpr bool operator==(G scalar, const Angle& angle) { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpEqual(scalar, angle.value_); + } else { + return scalar == angle.value_; + } + } + + // Three-way comparison operators ---------------------------------------------------------------- + template + [[nodiscard]] constexpr auto operator<=>(const Angle& other) const { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpThreeWay(value_, other.value_); + } else { + return value_ <=> other.value_; + } + } + template + [[nodiscard]] constexpr auto operator<=>(G scalar) const { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpThreeWay(value_, scalar); + } else { + return value_ <=> scalar; + } + } + + // Three-way comparison friend operator ---------------------------------------------------------- + template + [[nodiscard]] friend constexpr auto operator<=>(G lhs, const Angle& rhs) { + using H = common_floating_point_for_comparison_t; + + if constexpr (has_epsilon_v) { + return fuzzyCmpThreeWay(lhs, rhs.value_); + } else { + return lhs <=> rhs.value_; + } + } + + // Input/Output operators ------------------------------------------------------------------------ + friend inline std::istream& operator>>(std::istream& is, Angle& angle) { + return is >> angle.value_; + } + + friend inline std::ostream& operator<<(std::ostream& os, const Angle& angle) { + return os << angle.degrees() << "°"; + } + + private: + static constexpr type kDegreesToRadiansFactor = std::numbers::pi_v / 180; + static constexpr type kRadiansToDegreesFactor = 180 / std::numbers::pi_v; + + type value_{0}; +}; + +// Deduction guides -------------------------------------------------------------------------------- +template +Angle(T) -> Angle, T, double>>; + +// Literals ---------------------------------------------------------------------------------------- +inline namespace literals { +inline namespace angle_literals { + +static consteval Angle operator"" _deg(long double degrees) { + return Angle::fromDegrees(degrees); +} + +static consteval Angle +operator"" _deg(unsigned long long degrees) { // NOLINT(google-runtime-int) + return Angle::fromDegrees(degrees); +} + +static consteval Angle operator"" _rad(long double radians) { return Angle{radians}; } + +static consteval Angle +operator"" _rad(unsigned long long radians) { // NOLINT(google-runtime-int) + return Angle{static_cast(radians)}; +} + +} // namespace angle_literals +} // namespace literals + +} // namespace robocin + +#endif // ROBOCIN_GEOMETRY_ANGLE_H diff --git a/robocin/geometry/internal/angle_internal.h b/robocin/geometry/internal/angle_internal.h new file mode 100644 index 0000000..0767c31 --- /dev/null +++ b/robocin/geometry/internal/angle_internal.h @@ -0,0 +1,18 @@ +// +// Created by José Cruz on 13/04/23. +// Copyright (c) 2023 RobôCIn. +// + +#ifndef ROBOCIN_GEOMETRY_INTERNAL_ANGLE_INTERNAL_H +#define ROBOCIN_GEOMETRY_INTERNAL_ANGLE_INTERNAL_H + +#include + +namespace robocin::angle_internal { + +template +concept other_floating_point = std::floating_point and not std::same_as; + +} // namespace robocin::angle_internal + +#endif // ROBOCIN_GEOMETRY_INTERNAL_ANGLE_INTERNAL_H From e3e46062042b8e6238682c43c709c298859da975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cruz?= Date: Thu, 3 Aug 2023 17:55:34 -0300 Subject: [PATCH 2/3] Add CMakeLists.txt to Angle wrapper, rename differentiateWith method --- robocin/geometry/CMakeLists.txt | 6 ++++++ robocin/geometry/angle.h | 22 ++++++++++------------ robocin/geometry/internal/angle_internal.h | 4 +++- 3 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 robocin/geometry/CMakeLists.txt diff --git a/robocin/geometry/CMakeLists.txt b/robocin/geometry/CMakeLists.txt new file mode 100644 index 0000000..b750d52 --- /dev/null +++ b/robocin/geometry/CMakeLists.txt @@ -0,0 +1,6 @@ +robocin_cpp_library( + NAME angle + HDRS angle.h internal/angle_internal.h + SRCS angle.cpp + DEPS angular fuzzy_compare +) diff --git a/robocin/geometry/angle.h b/robocin/geometry/angle.h index 125d2b9..717a544 100644 --- a/robocin/geometry/angle.h +++ b/robocin/geometry/angle.h @@ -133,22 +133,20 @@ class Angle { [[nodiscard]] constexpr Angle normalized() && { return normalize(), std::move(*this); } [[nodiscard]] constexpr Angle normalized() const& { return Angle{*this}.normalized(); } - constexpr void differentiateWith(type other) & { value_ = smallestAngleDiff(value_, other); } - [[nodiscard]] constexpr Angle differentiatedWith(type other) && { - return differentiateWith(other), std::move(*this); + constexpr void smallestDiffTo(type other) & { value_ = smallestAngleDiff(value_, other); } + [[nodiscard]] constexpr Angle smallestDiffdTo(type other) && { + return smallestDiffTo(other), std::move(*this); } - [[nodiscard]] constexpr Angle differentiatedWith(type other) const& { - return Angle{*this}.differentiateWith(other); + [[nodiscard]] constexpr Angle smallestDiffdTo(type other) const& { + return Angle{*this}.smallestDiffdTo(other); } - constexpr void absDifferentiateWith(type other) & { - value_ = std::abs(smallestAngleDiff(value_, other)); + constexpr void absSmallestDiffTo(type other) & { value_ = absSmallestAngleDiff(value_, other); } + [[nodiscard]] constexpr Angle absSmallestDiffdTo(type other) && { + return absSmallestDiffTo(other), std::move(*this); } - [[nodiscard]] constexpr Angle absDifferentiatedWith(type other) && { - return absDifferentiateWith(other), std::move(*this); - } - [[nodiscard]] constexpr Angle absDifferentiatedWith(type other) const& { - return Angle{*this}.absDifferentiateWith(other); + [[nodiscard]] constexpr Angle absSmallestDiffdTo(type other) const& { + return Angle{*this}.absSmallestDiffdTo(other); } // Validators ------------------------------------------------------------------------------------ diff --git a/robocin/geometry/internal/angle_internal.h b/robocin/geometry/internal/angle_internal.h index 0767c31..a79bcf4 100644 --- a/robocin/geometry/internal/angle_internal.h +++ b/robocin/geometry/internal/angle_internal.h @@ -11,7 +11,9 @@ namespace robocin::angle_internal { template -concept other_floating_point = std::floating_point and not std::same_as; +concept other_floating_point = std::floating_point and // + std::floating_point and // + not std::same_as; } // namespace robocin::angle_internal From 661c7f0de0a0c253fa7a44f7ef9fe50c3f6b2aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cruz?= Date: Thu, 3 Aug 2023 18:05:26 -0300 Subject: [PATCH 3/3] Refactor smallestDiffTo method from Angle --- robocin/geometry/angle.h | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/robocin/geometry/angle.h b/robocin/geometry/angle.h index 717a544..13df0fa 100644 --- a/robocin/geometry/angle.h +++ b/robocin/geometry/angle.h @@ -6,16 +6,15 @@ #ifndef ROBOCIN_GEOMETRY_ANGLE_H #define ROBOCIN_GEOMETRY_ANGLE_H -#include -#include -#include - +#include "robocin/geometry/internal/angle_internal.h" #include "robocin/utility/angular.h" #include "robocin/utility/concepts.h" #include "robocin/utility/fuzzy_compare.h" #include "robocin/utility/type_traits.h" -#include "robocin/geometry/internal/angle_internal.h" +#include +#include +#include namespace robocin { @@ -133,20 +132,18 @@ class Angle { [[nodiscard]] constexpr Angle normalized() && { return normalize(), std::move(*this); } [[nodiscard]] constexpr Angle normalized() const& { return Angle{*this}.normalized(); } - constexpr void smallestDiffTo(type other) & { value_ = smallestAngleDiff(value_, other); } - [[nodiscard]] constexpr Angle smallestDiffdTo(type other) && { - return smallestDiffTo(other), std::move(*this); + [[nodiscard]] constexpr Angle smallestDiffTo(type other) && { + return value_ = smallestAngleDiff(value_, other), std::move(*this); } - [[nodiscard]] constexpr Angle smallestDiffdTo(type other) const& { - return Angle{*this}.smallestDiffdTo(other); + [[nodiscard]] constexpr Angle smallestDiffTo(type other) const& { + return Angle{*this}.smallestDiffTo(other); } - constexpr void absSmallestDiffTo(type other) & { value_ = absSmallestAngleDiff(value_, other); } - [[nodiscard]] constexpr Angle absSmallestDiffdTo(type other) && { - return absSmallestDiffTo(other), std::move(*this); + [[nodiscard]] constexpr Angle absSmallestDiffTo(type other) && { + return value_ = absSmallestAngleDiff(value_, other), std::move(*this); } - [[nodiscard]] constexpr Angle absSmallestDiffdTo(type other) const& { - return Angle{*this}.absSmallestDiffdTo(other); + [[nodiscard]] constexpr Angle absSmallestDiffTo(type other) const& { + return Angle{*this}.absSmallestDiffTo(other); } // Validators ------------------------------------------------------------------------------------