From 2a3e1f60353864aa516833b8c7d37d2709ba24bb Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 25 Dec 2022 17:32:29 +0100 Subject: [PATCH] refactor: `angular` system created --- src/core/include/units/generic/angle.h | 128 ------------------ src/core/include/units/generic/solid_angle.h | 104 -------------- src/systems/angular/CMakeLists.txt | 28 ++++ .../angular/include/units/angular/angular.h | 54 ++++++++ test/unit_test/runtime/math_test.cpp | 127 +++++++++++++++++ 5 files changed, 209 insertions(+), 232 deletions(-) delete mode 100644 src/core/include/units/generic/angle.h delete mode 100644 src/core/include/units/generic/solid_angle.h create mode 100644 src/systems/angular/CMakeLists.txt create mode 100644 src/systems/angular/include/units/angular/angular.h diff --git a/src/core/include/units/generic/angle.h b/src/core/include/units/generic/angle.h deleted file mode 100644 index b806ce4e..00000000 --- a/src/core/include/units/generic/angle.h +++ /dev/null @@ -1,128 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -// IWYU pragma: begin_exports -#include -#include -#include -// IWYU pragma: end_exports - -#include - -namespace units { - -struct radian : named_unit {}; -struct revolution : named_scaled_unit() * mag_pi, radian> {}; -struct degree : named_scaled_unit(), revolution> {}; -struct gradian : named_scaled_unit(), revolution> {}; - -template -struct dim_angle : base_dimension<"A", U> {}; - -template -concept Angle = QuantityOfT; - -template> U, Representation Rep = double> -using angle = quantity, U, Rep>; - -template -inline constexpr auto cotes_angle = angle(1); - -#ifndef UNITS_NO_LITERALS - -inline namespace literals { - -// rad -constexpr auto operator"" _q_rad(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return angle(static_cast(l)); -} -constexpr auto operator"" _q_rad(long double l) { return angle(l); } - -// rot -constexpr auto operator"" _q_rev(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return angle(static_cast(l)); -} -constexpr auto operator"" _q_rev(long double l) { return angle(l); } - -// deg -constexpr auto operator"" _q_deg(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return angle(static_cast(l)); -} -constexpr auto operator"" _q_deg(long double l) { return angle(l); } - -// grad -constexpr auto operator"" _q_grad(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return angle(static_cast(l)); -} -constexpr auto operator"" _q_grad(long double l) { return angle(l); } - -} // namespace literals - -#endif // UNITS_NO_LITERALS - -#ifndef UNITS_NO_REFERENCES - -namespace angle_references { - -inline constexpr auto rad = reference, radian>{}; -inline constexpr auto rev = reference, revolution>{}; -inline constexpr auto deg = reference, degree>{}; -inline constexpr auto grad = reference, gradian>{}; - -} // namespace angle_references - -namespace references { - -using namespace angle_references; - -} // namespace references - -#endif // UNITS_NO_REFERENCES - -} // namespace units - -#ifndef UNITS_NO_ALIASES - -namespace units::aliases::inline angle { - -template -using rad = units::angle; -template -using rev = units::angle; -template -using deg = units::angle; -template -using grad = units::angle; - -} // namespace units::aliases::inline angle - -#endif // UNITS_NO_ALIASES diff --git a/src/core/include/units/generic/solid_angle.h b/src/core/include/units/generic/solid_angle.h deleted file mode 100644 index eff9d388..00000000 --- a/src/core/include/units/generic/solid_angle.h +++ /dev/null @@ -1,104 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018 Mateusz Pusz -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#pragma once - -// IWYU pragma: begin_exports -#include -#include -#include -#include -// IWYU pragma: end_exports - -#include - -namespace units { - -struct steradian : named_unit {}; - -template -struct dim_solid_angle : derived_dimension, U, exponent, 2>> {}; - -struct square_degree : derived_scaled_unit, degree> {}; - -template -concept SolidAngle = QuantityOfT; - -template> U, Representation Rep = double> -using solid_angle = quantity, U, Rep>; - -#ifndef UNITS_NO_LITERALS - -inline namespace literals { - -// sr -constexpr auto operator"" _q_sr(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return solid_angle(static_cast(l)); -} -constexpr auto operator"" _q_sr(long double l) { return solid_angle(l); } - -// deg2 -constexpr auto operator"" _q_deg2(unsigned long long l) -{ - gsl_ExpectsAudit(std::in_range(l)); - return solid_angle(static_cast(l)); -} -constexpr auto operator"" _q_deg2(long double l) { return solid_angle(l); } - -} // namespace literals - -#endif // UNITS_NO_LITERALS - -#ifndef UNITS_NO_REFERENCES - -namespace solid_angle_references { - -inline constexpr auto sr = reference, steradian>{}; -inline constexpr auto deg2 = reference, square_degree>{}; - -} // namespace solid_angle_references - -namespace references { - -using namespace solid_angle_references; - -} // namespace references - -#endif // UNITS_NO_REFERENCES - -} // namespace units - -#ifndef UNITS_NO_ALIASES - -namespace units::aliases::inline solid_angle { - -template -using sr = units::solid_angle; - -template -using deg2 = units::solid_angle; - -} // namespace units::aliases::inline solid_angle - -#endif // UNITS_NO_ALIASES diff --git a/src/systems/angular/CMakeLists.txt b/src/systems/angular/CMakeLists.txt new file mode 100644 index 00000000..2ae65e6a --- /dev/null +++ b/src/systems/angular/CMakeLists.txt @@ -0,0 +1,28 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Mateusz Pusz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.19) + +add_units_module( + angular DEPENDENCIES mp-units::isq + HEADERS include/units/angular/angular.h +) diff --git a/src/systems/angular/include/units/angular/angular.h b/src/systems/angular/include/units/angular/angular.h new file mode 100644 index 00000000..426c5ef4 --- /dev/null +++ b/src/systems/angular/include/units/angular/angular.h @@ -0,0 +1,54 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace units::angular { + +// clang-format off +inline constexpr struct dim_angle : base_dimension<"A"> {} dim_angle; +QUANTITY_SPEC(angle, dim_angle); +QUANTITY_SPEC(solid_angle, pow<2>(angle)); + +inline constexpr struct radian : named_unit<"rad", angle> {} radian; +inline constexpr struct revolution : named_unit<"rev", mag<2> * mag_pi * radian> {} revolution; +inline constexpr struct degree : named_unit * revolution> {} degree; +inline constexpr struct gradian : named_unit * revolution> {} gradian; +inline constexpr struct steradian : named_unit<"sr", square> {} steradian; +// clang-format on + +namespace unit_symbols { + +inline constexpr auto rad = radian; +inline constexpr auto rev = revolution; +inline constexpr auto deg = degree; +inline constexpr auto grad = gradian; +inline constexpr auto sr = steradian; +inline constexpr auto deg2 = square; + +} // namespace unit_symbols + +} // namespace units::angular diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 3ed98f6d..6b0c016b 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -22,6 +22,7 @@ #include "almost_equals.h" #include +#include #include #include #include @@ -305,3 +306,129 @@ TEST_CASE("hypot functions", "[hypot]") REQUIRE(hypot(2. * isq::length[km], 3000. * isq::length[m], 6. * isq::length[km]) == 7. * isq::length[km]); } } + +TEST_CASE("ISQ trigonometric functions", "[trig][isq]") +{ + SECTION("sin") + { + REQUIRE_THAT(isq::sin(isq::angular_measure[deg](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(isq::sin(isq::angular_measure[deg](90.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(isq::sin(isq::angular_measure[deg](180.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(isq::sin(isq::angular_measure[deg](270.)), AlmostEquals(quantity{-1.})); + } + + SECTION("cos") + { + REQUIRE_THAT(isq::cos(isq::angular_measure[deg](0.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(isq::cos(isq::angular_measure[deg](90.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(isq::cos(isq::angular_measure[deg](180.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(isq::cos(isq::angular_measure[deg](270.)), AlmostEquals(quantity{0.})); + } + + SECTION("tan") + { + REQUIRE_THAT(isq::tan(isq::angular_measure[deg](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(isq::tan(isq::angular_measure[deg](45.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(isq::tan(isq::angular_measure[deg](135.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(isq::tan(isq::angular_measure[deg](180.)), AlmostEquals(quantity{0.})); + } +} + +TEST_CASE("ISQ inverse trigonometric functions", "[inv trig][isq]") +{ + SECTION("asin") + { + REQUIRE_THAT(isq::asin(quantity{-1.}), AlmostEquals(isq::angular_measure[deg](-90.))); + REQUIRE_THAT(isq::asin(quantity{0.}), AlmostEquals(isq::angular_measure[deg](0.))); + REQUIRE_THAT(isq::asin(quantity{1.}), AlmostEquals(isq::angular_measure[deg](90.))); + } + + SECTION("acos") + { + REQUIRE_THAT(isq::asin(quantity{-1.}), AlmostEquals(isq::angular_measure[deg](-90.))); + REQUIRE_THAT(isq::asin(quantity{0.}), AlmostEquals(isq::angular_measure[deg](0.))); + REQUIRE_THAT(isq::asin(quantity{1.}), AlmostEquals(isq::angular_measure[deg](90.))); + } + + SECTION("atan") + { + REQUIRE_THAT(isq::atan(quantity{-1.}), AlmostEquals(isq::angular_measure[deg](-45.))); + REQUIRE_THAT(isq::atan(quantity{0.}), AlmostEquals(isq::angular_measure[deg](0.))); + REQUIRE_THAT(isq::atan(quantity{1.}), AlmostEquals(isq::angular_measure[deg](45.))); + } +} + + +TEST_CASE("Angle trigonometric functions", "[trig][angle]") +{ + using namespace units::angular; + using namespace units::angular::unit_symbols; + using units::angular::unit_symbols::deg; + + SECTION("sin") + { + REQUIRE_THAT(sin(angle[deg](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(sin(angle[deg](90.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(sin(angle[deg](180.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(sin(angle[deg](270.)), AlmostEquals(quantity{-1.})); + + REQUIRE_THAT(sin(angle[grad](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(sin(angle[grad](100.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(sin(angle[grad](200.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(sin(angle[grad](300.)), AlmostEquals(quantity{-1.})); + } + + SECTION("cos") + { + REQUIRE_THAT(cos(angle[deg](0.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(cos(angle[deg](90.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(cos(angle[deg](180.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(cos(angle[deg](270.)), AlmostEquals(quantity{0.})); + + REQUIRE_THAT(cos(angle[grad](0.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(cos(angle[grad](100.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(cos(angle[grad](200.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(cos(angle[grad](300.)), AlmostEquals(quantity{0.})); + } + + SECTION("tan") + { + REQUIRE_THAT(tan(angle[deg](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(tan(angle[deg](45.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(tan(angle[deg](135.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(tan(angle[deg](180.)), AlmostEquals(quantity{0.})); + + REQUIRE_THAT(tan(angle[grad](0.)), AlmostEquals(quantity{0.})); + REQUIRE_THAT(tan(angle[grad](50.)), AlmostEquals(quantity{1.})); + REQUIRE_THAT(tan(angle[grad](150.)), AlmostEquals(quantity{-1.})); + REQUIRE_THAT(tan(angle[grad](200.)), AlmostEquals(quantity{0.})); + } +} + +TEST_CASE("Angle inverse trigonometric functions", "[inv trig][angle]") +{ + using namespace units::angular; + using namespace units::angular::unit_symbols; + using units::angular::unit_symbols::deg; + + SECTION("asin") + { + REQUIRE_THAT(asin(quantity{-1.}), AlmostEquals(angle[deg](-90.))); + REQUIRE_THAT(asin(quantity{0.}), AlmostEquals(angle[deg](0.))); + REQUIRE_THAT(asin(quantity{1.}), AlmostEquals(angle[deg](90.))); + } + + SECTION("acos") + { + REQUIRE_THAT(asin(quantity{-1.}), AlmostEquals(angle[deg](-90.))); + REQUIRE_THAT(asin(quantity{0.}), AlmostEquals(angle[deg](0.))); + REQUIRE_THAT(asin(quantity{1.}), AlmostEquals(angle[deg](90.))); + } + + SECTION("atan") + { + REQUIRE_THAT(atan(quantity{-1.}), AlmostEquals(angle[deg](-45.))); + REQUIRE_THAT(atan(quantity{0.}), AlmostEquals(angle[deg](0.))); + REQUIRE_THAT(atan(quantity{1.}), AlmostEquals(angle[deg](45.))); + } +}