From b982921d271c516af9edb695cf696eef72d10152 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 6 Apr 2021 15:57:28 +0200 Subject: [PATCH] refactor: References are now guarded `UNITS_REFERENCES` with (ON by default) + examples duplicated to subdirectories Now References can be disabled to meassure a compile time impact. Also the same examples are now provided in two subdirectories to be able to easily compare the pros and cons of every quantity construction technique. --- README.md | 2 - conanfile.py | 5 +- docs/Doxyfile.in | 11 + docs/examples/avg_speed.rst | 2 +- docs/examples/box_example.rst | 2 +- docs/examples/capacitor_time_curve.rst | 2 +- docs/examples/clcpp_response.rst | 2 +- docs/examples/conversion_factor.rst | 2 +- docs/examples/custom_systems.rst | 2 +- docs/examples/foot_pound_second.rst | 2 +- docs/examples/glide_computer.rst | 12 +- ...lman_filter-alpha_beta_filter_example2.rst | 2 +- docs/examples/linear_algebra.rst | 2 +- docs/examples/measurement.rst | 2 +- docs/examples/total_energy.rst | 2 +- docs/examples/unknown_dimension.rst | 2 +- docs/framework/quantities.rst | 8 +- docs/quick_start.rst | 2 - docs/usage.rst | 19 + example/CMakeLists.txt | 45 +-- example/hello_units.cpp | 2 - example/literals/CMakeLists.txt | 60 +++ example/literals/avg_speed.cpp | 193 ++++++++++ example/literals/box_example.cpp | 113 ++++++ example/literals/capacitor_time_curve.cpp | 63 +++ example/literals/clcpp_response.cpp | 150 ++++++++ example/literals/conversion_factor.cpp | 60 +++ example/{ => literals}/custom_systems.cpp | 0 example/literals/experimental_angle.cpp | 44 +++ example/literals/foot_pound_second.cpp | 99 +++++ example/literals/geographic.cpp | 63 +++ example/literals/geographic.h | 139 +++++++ example/{ => literals}/glide_computer.cpp | 0 example/{ => literals}/glide_computer.h | 0 example/literals/glide_computer_example.cpp | 202 ++++++++++ ...lman_filter-alpha_beta_filter_example2.cpp | 100 +++++ example/literals/linear_algebra.cpp | 361 ++++++++++++++++++ example/{ => literals}/measurement.cpp | 0 example/literals/total_energy.cpp | 104 +++++ example/literals/unknown_dimension.cpp | 72 ++++ example/references/CMakeLists.txt | 60 +++ example/{ => references}/avg_speed.cpp | 0 example/{ => references}/box_example.cpp | 0 .../{ => references}/capacitor_time_curve.cpp | 0 example/{ => references}/clcpp_response.cpp | 0 .../{ => references}/conversion_factor.cpp | 0 example/references/custom_systems.cpp | 113 ++++++ .../{ => references}/experimental_angle.cpp | 0 .../{ => references}/foot_pound_second.cpp | 0 example/{ => references}/geographic.cpp | 0 example/{ => references}/geographic.h | 0 example/references/glide_computer.cpp | 166 ++++++++ example/references/glide_computer.h | 218 +++++++++++ .../glide_computer_example.cpp | 0 ...lman_filter-alpha_beta_filter_example2.cpp | 0 example/{ => references}/linear_algebra.cpp | 0 example/references/measurement.cpp | 157 ++++++++ example/{ => references}/total_energy.cpp | 0 .../{ => references}/unknown_dimension.cpp | 0 src/CMakeLists.txt | 2 + src/cmake/AddUnitsModule.cmake | 5 +- src/core/CMakeLists.txt | 5 +- src/core/include/units/generic/angle.h | 4 + .../units/isq/iec80000/modulation_rate.h | 4 + .../units/isq/iec80000/storage_capacity.h | 4 + .../units/isq/iec80000/traffic_intensity.h | 4 + .../include/units/isq/si/cgs/acceleration.h | 4 + .../si-cgs/include/units/isq/si/cgs/area.h | 4 + .../si-cgs/include/units/isq/si/cgs/energy.h | 4 + .../si-cgs/include/units/isq/si/cgs/force.h | 4 + .../si-cgs/include/units/isq/si/cgs/length.h | 4 + .../si-cgs/include/units/isq/si/cgs/mass.h | 4 + .../include/units/isq/si/cgs/pressure.h | 4 + .../si-cgs/include/units/isq/si/cgs/time.h | 4 + .../si-fps/include/units/isq/si/fps/area.h | 4 + .../si-fps/include/units/isq/si/fps/force.h | 4 + .../si-fps/include/units/isq/si/fps/length.h | 4 + .../si-fps/include/units/isq/si/fps/mass.h | 4 + .../si-fps/include/units/isq/si/fps/power.h | 4 + .../include/units/isq/si/fps/pressure.h | 4 + .../si-fps/include/units/isq/si/fps/speed.h | 4 + .../si-fps/include/units/isq/si/fps/time.h | 4 + .../si-fps/include/units/isq/si/fps/volume.h | 4 + .../si-iau/include/units/isq/si/iau/length.h | 4 + .../include/units/isq/si/imperial/length.h | 4 + .../include/units/isq/si/international/area.h | 4 + .../units/isq/si/international/length.h | 4 + .../units/isq/si/international/volume.h | 4 + .../include/units/isq/si/typographic/length.h | 4 + .../si-us/include/units/isq/si/us/length.h | 4 + .../si/include/units/isq/si/absorbed_dose.h | 4 + .../units/isq/si/amount_of_substance.h | 4 + src/systems/si/include/units/isq/si/area.h | 4 + .../si/include/units/isq/si/capacitance.h | 4 + .../include/units/isq/si/catalytic_activity.h | 4 + .../si/include/units/isq/si/conductance.h | 4 + .../si/include/units/isq/si/electric_charge.h | 4 + .../include/units/isq/si/electric_current.h | 4 + src/systems/si/include/units/isq/si/energy.h | 4 + src/systems/si/include/units/isq/si/force.h | 4 + .../si/include/units/isq/si/frequency.h | 4 + .../si/include/units/isq/si/inductance.h | 4 + src/systems/si/include/units/isq/si/length.h | 4 + .../include/units/isq/si/luminous_intensity.h | 4 + .../si/include/units/isq/si/magnetic_flux.h | 4 + .../include/units/isq/si/magnetic_induction.h | 4 + src/systems/si/include/units/isq/si/mass.h | 9 +- src/systems/si/include/units/isq/si/power.h | 4 + .../si/include/units/isq/si/pressure.h | 4 + .../si/include/units/isq/si/radioactivity.h | 4 + .../si/include/units/isq/si/resistance.h | 4 + .../units/isq/si/thermodynamic_temperature.h | 4 + src/systems/si/include/units/isq/si/time.h | 4 + src/systems/si/include/units/isq/si/voltage.h | 4 + src/systems/si/include/units/isq/si/volume.h | 4 + test/unit_test/runtime/CMakeLists.txt | 5 +- test/unit_test/static/CMakeLists.txt | 10 +- test_package/CMakeLists.txt | 1 + 118 files changed, 2841 insertions(+), 71 deletions(-) create mode 100644 example/literals/CMakeLists.txt create mode 100644 example/literals/avg_speed.cpp create mode 100644 example/literals/box_example.cpp create mode 100644 example/literals/capacitor_time_curve.cpp create mode 100644 example/literals/clcpp_response.cpp create mode 100644 example/literals/conversion_factor.cpp rename example/{ => literals}/custom_systems.cpp (100%) create mode 100644 example/literals/experimental_angle.cpp create mode 100644 example/literals/foot_pound_second.cpp create mode 100644 example/literals/geographic.cpp create mode 100644 example/literals/geographic.h rename example/{ => literals}/glide_computer.cpp (100%) rename example/{ => literals}/glide_computer.h (100%) create mode 100644 example/literals/glide_computer_example.cpp create mode 100644 example/literals/kalman_filter-alpha_beta_filter_example2.cpp create mode 100644 example/literals/linear_algebra.cpp rename example/{ => literals}/measurement.cpp (100%) create mode 100644 example/literals/total_energy.cpp create mode 100644 example/literals/unknown_dimension.cpp create mode 100644 example/references/CMakeLists.txt rename example/{ => references}/avg_speed.cpp (100%) rename example/{ => references}/box_example.cpp (100%) rename example/{ => references}/capacitor_time_curve.cpp (100%) rename example/{ => references}/clcpp_response.cpp (100%) rename example/{ => references}/conversion_factor.cpp (100%) create mode 100644 example/references/custom_systems.cpp rename example/{ => references}/experimental_angle.cpp (100%) rename example/{ => references}/foot_pound_second.cpp (100%) rename example/{ => references}/geographic.cpp (100%) rename example/{ => references}/geographic.h (100%) create mode 100644 example/references/glide_computer.cpp create mode 100644 example/references/glide_computer.h rename example/{ => references}/glide_computer_example.cpp (100%) rename example/{ => references}/kalman_filter-alpha_beta_filter_example2.cpp (100%) rename example/{ => references}/linear_algebra.cpp (100%) create mode 100644 example/references/measurement.cpp rename example/{ => references}/total_energy.cpp (100%) rename example/{ => references}/unknown_dimension.cpp (100%) diff --git a/README.md b/README.md index 36e323db..091a123a 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,6 @@ and dimensional analysis can be performed without sacrificing on accuracy. Pleas the below example for a quick preview of basic library features: ```cpp -#define UNITS_LITERALS - #include #include #include diff --git a/conanfile.py b/conanfile.py index 32fa1f6e..2940d0d6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -41,11 +41,13 @@ class UnitsConan(ConanFile): "gsl-lite/0.37.0" ) options = { + "references": [True, False], "literals": [True, False], "downcast_mode": ["off", "on", "auto"], "build_docs": [True, False] } default_options = { + "references": True, "literals": False, "downcast_mode": "on", "build_docs": True @@ -118,7 +120,8 @@ class UnitsConan(ConanFile): def generate(self): tc = CMakeToolchain(self) - tc.variables["UNITS_LITERALS"] = self.options.udls + tc.variables["UNITS_REFERENCES"] = self.options.references + tc.variables["UNITS_LITERALS"] = self.options.literals tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() # if self._run_tests: # TODO Enable this when environment is supported in the Conan toolchain tc.variables["UNITS_BUILD_DOCS"] = self.options.build_docs diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 9dec7d17..72e86f3e 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -91,3 +91,14 @@ WARN_AS_ERROR = NO # The default value is: NO. QUIET = YES + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = UNITS_REFERENCES \ + UNITS_LITERALS diff --git a/docs/examples/avg_speed.rst b/docs/examples/avg_speed.rst index d4a18de5..9eceb60a 100644 --- a/docs/examples/avg_speed.rst +++ b/docs/examples/avg_speed.rst @@ -1,7 +1,7 @@ avg_speed ========= -.. literalinclude:: ../../example/avg_speed.cpp +.. literalinclude:: ../../example/references/avg_speed.cpp :caption: avg_speed.cpp :start-at: #include :linenos: diff --git a/docs/examples/box_example.rst b/docs/examples/box_example.rst index b25d8921..86fb9b7c 100644 --- a/docs/examples/box_example.rst +++ b/docs/examples/box_example.rst @@ -1,7 +1,7 @@ box_example =========== -.. literalinclude:: ../../example/box_example.cpp +.. literalinclude:: ../../example/references/box_example.cpp :caption: box_example.cpp :start-at: #include :linenos: diff --git a/docs/examples/capacitor_time_curve.rst b/docs/examples/capacitor_time_curve.rst index 779865e3..26fdf7cd 100644 --- a/docs/examples/capacitor_time_curve.rst +++ b/docs/examples/capacitor_time_curve.rst @@ -1,7 +1,7 @@ capacitor_time_curve ==================== -.. literalinclude:: ../../example/capacitor_time_curve.cpp +.. literalinclude:: ../../example/references/capacitor_time_curve.cpp :caption: capacitor_time_curve.cpp :start-at: #include :linenos: diff --git a/docs/examples/clcpp_response.rst b/docs/examples/clcpp_response.rst index 4419b84a..e77b4189 100644 --- a/docs/examples/clcpp_response.rst +++ b/docs/examples/clcpp_response.rst @@ -1,7 +1,7 @@ clcpp_response ============== -.. literalinclude:: ../../example/clcpp_response.cpp +.. literalinclude:: ../../example/references/clcpp_response.cpp :caption: clcpp_response.cpp :start-at: #include :linenos: diff --git a/docs/examples/conversion_factor.rst b/docs/examples/conversion_factor.rst index 21bbefc5..e2709215 100644 --- a/docs/examples/conversion_factor.rst +++ b/docs/examples/conversion_factor.rst @@ -1,7 +1,7 @@ conversion_factor ================= -.. literalinclude:: ../../example/conversion_factor.cpp +.. literalinclude:: ../../example/references/conversion_factor.cpp :caption: conversion_factor.cpp :start-at: #include :linenos: diff --git a/docs/examples/custom_systems.rst b/docs/examples/custom_systems.rst index a4e93583..e93e0c4b 100644 --- a/docs/examples/custom_systems.rst +++ b/docs/examples/custom_systems.rst @@ -1,7 +1,7 @@ custom_systems ============== -.. literalinclude:: ../../example/custom_systems.cpp +.. literalinclude:: ../../example/references/custom_systems.cpp :caption: custom_systems.cpp :start-at: #include :linenos: diff --git a/docs/examples/foot_pound_second.rst b/docs/examples/foot_pound_second.rst index 23c694e9..ba10e747 100644 --- a/docs/examples/foot_pound_second.rst +++ b/docs/examples/foot_pound_second.rst @@ -1,7 +1,7 @@ foot_pound_second ================= -.. literalinclude:: ../../example/foot_pound_second.cpp +.. literalinclude:: ../../example/references/foot_pound_second.cpp :caption: foot_pound_second.cpp :start-at: #include :linenos: diff --git a/docs/examples/glide_computer.rst b/docs/examples/glide_computer.rst index d18b34f4..a8f31d04 100644 --- a/docs/examples/glide_computer.rst +++ b/docs/examples/glide_computer.rst @@ -13,7 +13,7 @@ This example presents the usage of: - quantities text output formatting, - cooperation with `std::chrono`. -.. literalinclude:: ../../example/glide_computer.h +.. literalinclude:: ../../example/references/glide_computer.h :caption: glide_computer.h :start-at: #include :end-before: using namespace units; @@ -35,7 +35,7 @@ For example we have 3 for a quantity of length: - ``height`` - a relative altitude difference between 2 points in the air - ``altitude`` - an absolute altitude value measured form the mean sea level (AMSL). -.. literalinclude:: ../../example/glide_computer.h +.. literalinclude:: ../../example/references/glide_computer.h :caption: glide_computer.h :start-at: using namespace units; :end-before: // text output @@ -44,7 +44,7 @@ For example we have 3 for a quantity of length: Next a custom text output is provided both for C++ output streams and the text formatting facility. -.. literalinclude:: ../../example/glide_computer.h +.. literalinclude:: ../../example/references/glide_computer.h :caption: glide_computer.h :start-at: // text output :end-before: // definition of glide computer databases and utilities @@ -58,13 +58,13 @@ convert it to the one required by the engine interface. The glide calculator takes task created as a list of waypoints, glider performance data, weather conditions, safety constraints, and a towing height. -.. literalinclude:: ../../example/glide_computer.h +.. literalinclude:: ../../example/references/glide_computer.h :caption: glide_computer.h :start-at: // definition of glide computer databases and utilities :linenos: :lineno-match: -.. literalinclude:: ../../example/glide_computer_example.cpp +.. literalinclude:: ../../example/references/glide_computer_example.cpp :caption: glide_computer_example.cpp :start-at: #include :linenos: @@ -74,7 +74,7 @@ Having all of that it estimates the number of flight phases (towing, circling, g needed to finish a task. As an output it provides the duration needed to finish the task while flying a selected glider in the specific weather conditions. -.. literalinclude:: ../../example/glide_computer.cpp +.. literalinclude:: ../../example/references/glide_computer.cpp :caption: glide_computer.cpp :start-at: #include :linenos: diff --git a/docs/examples/kalman_filter-alpha_beta_filter_example2.rst b/docs/examples/kalman_filter-alpha_beta_filter_example2.rst index 9db65572..3643ccfe 100644 --- a/docs/examples/kalman_filter-alpha_beta_filter_example2.rst +++ b/docs/examples/kalman_filter-alpha_beta_filter_example2.rst @@ -4,7 +4,7 @@ kalman_filter-alpha_beta_filter_example2 This example is based on the 1d aircraft α-β filter example 2 from the `Kalman Filter `_ tutorial. -.. literalinclude:: ../../example/kalman_filter-alpha_beta_filter_example2.cpp +.. literalinclude:: ../../example/references/kalman_filter-alpha_beta_filter_example2.cpp :caption: kalman_filter-alpha_beta_filter_example2.cpp :start-at: #include :linenos: diff --git a/docs/examples/linear_algebra.rst b/docs/examples/linear_algebra.rst index 21bef28b..07f4c0fc 100644 --- a/docs/examples/linear_algebra.rst +++ b/docs/examples/linear_algebra.rst @@ -1,7 +1,7 @@ linear_algebra ============== -.. literalinclude:: ../../example/linear_algebra.cpp +.. literalinclude:: ../../example/references/linear_algebra.cpp :caption: linear_algebra.cpp :start-at: #include :linenos: diff --git a/docs/examples/measurement.rst b/docs/examples/measurement.rst index c0496e1e..c45e3dfa 100644 --- a/docs/examples/measurement.rst +++ b/docs/examples/measurement.rst @@ -1,7 +1,7 @@ measurement =========== -.. literalinclude:: ../../example/measurement.cpp +.. literalinclude:: ../../example/references/measurement.cpp :caption: measurement.cpp :start-at: #include :linenos: diff --git a/docs/examples/total_energy.rst b/docs/examples/total_energy.rst index ba31816f..1ea5627e 100644 --- a/docs/examples/total_energy.rst +++ b/docs/examples/total_energy.rst @@ -1,7 +1,7 @@ total_energy ============ -.. literalinclude:: ../../example/total_energy.cpp +.. literalinclude:: ../../example/references/total_energy.cpp :caption: total_energy.cpp :start-at: #include :linenos: diff --git a/docs/examples/unknown_dimension.rst b/docs/examples/unknown_dimension.rst index d0241439..9d39427b 100644 --- a/docs/examples/unknown_dimension.rst +++ b/docs/examples/unknown_dimension.rst @@ -1,7 +1,7 @@ unknown_dimension ================= -.. literalinclude:: ../../example/unknown_dimension.cpp +.. literalinclude:: ../../example/references/unknown_dimension.cpp :caption: unknown_dimension.cpp :start-at: #include :linenos: diff --git a/docs/framework/quantities.rst b/docs/framework/quantities.rst index 38892581..b003bc94 100644 --- a/docs/framework/quantities.rst +++ b/docs/framework/quantities.rst @@ -56,6 +56,8 @@ Quantity References Quantity References provide an alternative and simplified way to create quantities. They are defined using the `reference` class template:: + #ifdef UNITS_REFERENCES + namespace references { inline constexpr auto km = reference{}; @@ -63,6 +65,8 @@ They are defined using the `reference` class template:: } + #endif // UNITS_REFERENCES + With the above our code can look as follows:: using namespace units::isq::si::references; @@ -103,8 +107,6 @@ Alternatively, to construct quantities with compile-time known values the librar Thanks to them the same code can be as simple as:: - #define UNITS_LITERALS - using namespace units::isq::si::literals; auto d = 123._q_km; // si::length auto v = 70_q_km_per_h; // si::speed @@ -122,7 +124,7 @@ Thanks to them the same code can be as simple as:: As one can read in the next section UDLs, are considered to be inferior to `Quantity References`_ and their definition affects compile-time performance a lot. This is why they are an opt-in feature - of the library and in order to use them one has to provide a `UNITS_UDL` preprocessor definition. + of the library and in order to use them one has to provide a `UNITS_LITERALS` preprocessor definition. UDLs vs Quantity References diff --git a/docs/quick_start.rst b/docs/quick_start.rst index 4b0745e4..cfb1a0b0 100644 --- a/docs/quick_start.rst +++ b/docs/quick_start.rst @@ -40,8 +40,6 @@ but still easy to use interface where all unit conversions and dimensional analy performed without sacrificing on accuracy. Please see the below example for a quick preview of basic library features:: - #define UNITS_LITERALS - #include #include #include diff --git a/docs/usage.rst b/docs/usage.rst index cbca6aef..83ef4fab 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -123,6 +123,15 @@ It also runs unit tests during Conan build. Conan Options ^^^^^^^^^^^^^ +references +++++++++++ + +**Values**: ``True``/``False`` + +**Defaulted to**: ``True`` + +Determines if library should provide Quantity References for quantities of various units. + literals ++++++++ @@ -158,6 +167,16 @@ Additionally, enables project documentation generation when the project is being CMake Options ^^^^^^^^^^^^^ +UNITS_REFERENCES +++++++++++++++++ + +**Values**: ``ON``/``OFF`` + +**Defaulted to**: ``ON`` + +Equivalent to `references`_. + + UNITS_LITERALS ++++++++++++++ diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index e28873d9..549fcf25 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -22,40 +22,13 @@ cmake_minimum_required(VERSION 3.2) -# -# add_example(target ...) -# -function(add_example target) - add_executable(${target} ${target}.cpp) - target_link_libraries(${target} PRIVATE ${ARGN}) -endfunction() - -add_example(avg_speed mp-units::core-io mp-units::si mp-units::si-cgs mp-units::si-international) -add_example(box_example mp-units::core-fmt mp-units::si) -add_example(capacitor_time_curve mp-units::core-io mp-units::si) -add_example(clcpp_response mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-iau mp-units::si-imperial mp-units::si-international mp-units::si-typographic mp-units::si-us) -add_example(conversion_factor mp-units::core-fmt mp-units::core-io mp-units::si) -add_example(custom_systems mp-units::core-io mp-units::si) -add_example(experimental_angle mp-units::core-fmt mp-units::core-io mp-units::si) -add_example(foot_pound_second mp-units::core-fmt mp-units::si-fps) -add_example(hello_units mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-international) -add_example(kalman_filter-alpha_beta_filter_example2 mp-units::core-fmt mp-units::si) -add_example(measurement mp-units::core-io mp-units::si) -add_example(total_energy mp-units::core-io mp-units::si mp-units::isq-natural) -add_example(unknown_dimension mp-units::core-io mp-units::si) - -if(NOT UNITS_LIBCXX) - add_executable(glide_computer - geographic.cpp geographic.h - glide_computer.cpp glide_computer.h - glide_computer_example.cpp - ) - target_link_libraries(glide_computer PRIVATE mp-units::core-fmt mp-units::si mp-units::si-international) - target_include_directories(glide_computer PRIVATE ${CMAKE_CURRENT_LIST_DIR}) - - find_package(linear_algebra CONFIG REQUIRED) - add_example(linear_algebra mp-units::core-fmt mp-units::core-io mp-units::si) - target_link_libraries(linear_algebra PRIVATE linear_algebra::linear_algebra) -endif() - add_subdirectory(alternative_namespaces) +add_subdirectory(literals) +add_subdirectory(references) + +add_executable(hello_units hello_units.cpp) +target_link_libraries(hello_units PRIVATE mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-international) +target_compile_definitions(hello_units PRIVATE + UNITS_REFERENCES + UNITS_LITERALS +) diff --git a/example/hello_units.cpp b/example/hello_units.cpp index a182b5c4..b7513dbd 100644 --- a/example/hello_units.cpp +++ b/example/hello_units.cpp @@ -20,8 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#define UNITS_LITERALS - #include #include #include // IWYU pragma: keep diff --git a/example/literals/CMakeLists.txt b/example/literals/CMakeLists.txt new file mode 100644 index 00000000..380a0b2a --- /dev/null +++ b/example/literals/CMakeLists.txt @@ -0,0 +1,60 @@ +# 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.2) + +# +# add_example(target ...) +# +function(add_example target) + add_executable(${target}-literals ${target}.cpp) + target_link_libraries(${target}-literals PRIVATE ${ARGN}) + target_compile_definitions(${target}-literals PRIVATE UNITS_LITERALS) +endfunction() + +add_example(avg_speed mp-units::core-io mp-units::si mp-units::si-cgs mp-units::si-international) +add_example(box_example mp-units::core-fmt mp-units::si) +add_example(capacitor_time_curve mp-units::core-io mp-units::si) +add_example(clcpp_response mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-iau mp-units::si-imperial mp-units::si-international mp-units::si-typographic mp-units::si-us) +add_example(conversion_factor mp-units::core-fmt mp-units::core-io mp-units::si) +add_example(custom_systems mp-units::core-io mp-units::si) +add_example(experimental_angle mp-units::core-fmt mp-units::core-io mp-units::si) +add_example(foot_pound_second mp-units::core-fmt mp-units::si-fps) +add_example(kalman_filter-alpha_beta_filter_example2 mp-units::core-fmt mp-units::si) +add_example(measurement mp-units::core-io mp-units::si) +add_example(total_energy mp-units::core-io mp-units::si mp-units::isq-natural) +add_example(unknown_dimension mp-units::core-io mp-units::si) + +if(NOT UNITS_LIBCXX) + add_executable(glide_computer-literals + geographic.cpp geographic.h + glide_computer.cpp glide_computer.h + glide_computer_example.cpp + ) + target_link_libraries(glide_computer-literals PRIVATE mp-units::core-fmt mp-units::si mp-units::si-international) + target_include_directories(glide_computer-literals PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + target_compile_definitions(glide_computer-literals PRIVATE UNITS_LITERALS) + + find_package(linear_algebra CONFIG REQUIRED) + add_example(linear_algebra mp-units::core-fmt mp-units::core-io mp-units::si) + target_link_libraries(linear_algebra-literals PRIVATE linear_algebra::linear_algebra) +endif() diff --git a/example/literals/avg_speed.cpp b/example/literals/avg_speed.cpp new file mode 100644 index 00000000..e00d90d7 --- /dev/null +++ b/example/literals/avg_speed.cpp @@ -0,0 +1,193 @@ +// 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. + +#include +#include // IWYU pragma: keep +#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include +#include +#include +#include +#include + +namespace { + +using namespace units::isq; + +constexpr si::speed +fixed_int_si_avg_speed(si::length d, + si::time t) +{ + return d / t; +} + +constexpr si::speed +fixed_double_si_avg_speed(si::length d, + si::time t) +{ + return d / t; +} + +template +constexpr Speed auto si_avg_speed(si::length d, + si::time t) +{ + return d / t; +} + +constexpr Speed auto avg_speed(Length auto d, Time auto t) +{ + return d / t; +} + +template +void print_result(D distance, T duration, V speed) +{ + const auto result_in_kmph = units::quantity_cast>(speed); + std::cout << "Average speed of a car that makes " << distance << " in " + << duration << " is " << result_in_kmph << ".\n"; +} + +void example() +{ + // SI (int) + { + using namespace units::isq::si::literals; + constexpr Length auto distance = 220_q_km; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "SI units with 'int' as representation\n"; + + print_result(distance, duration, fixed_int_si_avg_speed(distance, duration)); + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } + + // SI (double) + { + using namespace units::isq::si::literals; + constexpr Length auto distance = 220._q_km; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nSI units with 'double' as representation\n"; + + // conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), quantity_cast(duration))); + + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } + + // Customary Units (int) + { + using namespace units::isq::si::international::literals; + constexpr Length auto distance = 140_q_mi; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nUS Customary Units with 'int' as representation\n"; + + // it is not possible to make a lossless conversion of miles to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), duration)); + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } + + // Customary Units (double) + { + using namespace units::isq::si::international::literals; + constexpr Length auto distance = 140._q_mi; // constructed from a UDL + constexpr si::time duration(2); // constructed from a value + + std::cout << "\nUS Customary Units with 'double' as representation\n"; + + // conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed + // also it is not possible to make a lossless conversion of miles to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast>(distance), quantity_cast(duration))); + + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + print_result(distance, duration, si_avg_speed(distance, duration)); + print_result(distance, duration, avg_speed(distance, duration)); + } + + // CGS (int) + { + using namespace units::isq::si::cgs::literals; + constexpr Length auto distance = 22'000'000_q_cm; // constructed from a UDL + constexpr si::cgs::time duration(2); // constructed from a value + + std::cout << "\nCGS units with 'int' as representation\n"; + + // it is not possible to make a lossless conversion of centimeters to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast(distance), duration)); + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + + // not possible to convert both a dimension and a unit with implicit cast + print_result(distance, duration, si_avg_speed(quantity_cast(distance), duration)); + + print_result(distance, duration, avg_speed(distance, duration)); + } + + // CGS (double) + { + using namespace units::isq::si::cgs::literals; + constexpr Length auto distance = 22'000'000._q_cm; // constructed from a UDL + constexpr si::cgs::time duration(2); // constructed from a value + + std::cout << "\nCGS units with 'double' as representation\n"; + + // conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed + // it is not possible to make a lossless conversion of centimeters to meters on an integral type + // (explicit cast needed) + print_result(distance, duration, fixed_int_si_avg_speed(quantity_cast>(distance), quantity_cast(duration))); + + print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); + + // not possible to convert both a dimension and a unit with implicit cast + print_result(distance, duration, si_avg_speed(quantity_cast(distance), duration)); + + print_result(distance, duration, avg_speed(distance, duration)); + } + +} + +} // namespace + +int main() +{ + try { + example(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/literals/box_example.cpp b/example/literals/box_example.cpp new file mode 100644 index 00000000..0e7afbaf --- /dev/null +++ b/example/literals/box_example.cpp @@ -0,0 +1,113 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include + +namespace { + +using namespace units::isq; + +using m = si::metre; +using m2 = si::square_metre; +using m3 = si::cubic_metre; +using kg = si::kilogram; +using N = si::newton; +using kgpm3 = si::kilogram_per_metre_cub; + +inline constexpr auto g = si::si2019::standard_gravity<>; +inline constexpr si::density air_density(1.225); + + +class Box { + si::area base_; + si::length height_; + si::density density_ = air_density; +public: + constexpr Box(const si::length& length, const si::length& width, si::length height) : base_(length * width), height_(std::move(height)) {} + + [[nodiscard]] constexpr si::force filled_weight() const + { + const si::volume volume = base_ * height_; + const si::mass mass = density_ * volume; + return mass * g; + } + + [[nodiscard]] constexpr si::length fill_level(const si::mass& measured_mass) const + { + return height_ * measured_mass * g / filled_weight(); + } + + [[nodiscard]] constexpr si::volume spare_capacity(const si::mass& measured_mass) const + { + return (height_ - fill_level(measured_mass)) * base_; + } + + constexpr void set_contents_density(const si::density& density_in) + { + assert(density_in > air_density); + density_ = density_in; + } +}; + +} // namespace + + +int main() +{ + using namespace units; + using namespace si::literals; + + const si::length height(200.0_q_mm); + auto box = Box(1000.0_q_mm, 500.0_q_mm, height); + box.set_contents_density(1000.0_q_kg_per_m3); + + const auto fill_time = 200.0_q_s; // time since starting fill + const auto measured_mass = 20.0_q_kg; // measured mass at fill_time + + const Length auto fill_level = box.fill_level(measured_mass); + const Dimensionless auto fill_percent = quantity_cast(fill_level / height); + const Volume auto spare_capacity = box.spare_capacity(measured_mass); + const auto input_flow_rate = measured_mass / fill_time; // unknown dimension + const Speed auto float_rise_rate = fill_level / fill_time; + const Time auto fill_time_left = (height / fill_level - 1) * fill_time; + + std::cout << "mp-units box example...\n"; + std::cout << fmt::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); + std::cout << fmt::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); + std::cout << fmt::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); + std::cout << fmt::format("float rise rate = {}\n", float_rise_rate); + std::cout << fmt::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); +} diff --git a/example/literals/capacitor_time_curve.cpp b/example/literals/capacitor_time_curve.cpp new file mode 100644 index 00000000..e1300e91 --- /dev/null +++ b/example/literals/capacitor_time_curve.cpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2003-2020 Andy Little. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses./ +*/ + +/* + capacitor discharge curve using compile_time + physical_quantities +*/ + +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include + +int main() +{ + using namespace units::isq; + using namespace units::isq::si; + + std::cout << "mp-units capacitor time curve example...\n"; + std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); + std::cout.precision(3); + + constexpr auto C = 0.47_q_uF; + constexpr auto V0 = 5.0_q_V; + constexpr auto R = 4.7_q_kR; + + for (auto t = 0_q_ms; t <= 50_q_ms; ++t) { + const Voltage auto Vt = V0 * units::exp(-t / (R * C)); + + std::cout << "at " << t << " voltage is "; + + if (Vt >= 1_q_V) + std::cout << Vt; + else if (Vt >= 1_q_mV) + std::cout << quantity_cast(Vt); + else if (Vt >= 1_q_uV) + std::cout << quantity_cast(Vt); + else if (Vt >= 1_q_nV) + std::cout << quantity_cast(Vt); + else + std::cout << quantity_cast(Vt); + std::cout << "\n"; + } +} diff --git a/example/literals/clcpp_response.cpp b/example/literals/clcpp_response.cpp new file mode 100644 index 00000000..6a130b2f --- /dev/null +++ b/example/literals/clcpp_response.cpp @@ -0,0 +1,150 @@ +/* + Copyright (c) 2003-2019 Andy Little. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses./ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using namespace units; + +void simple_quantities() +{ + using namespace units::isq::si; + using namespace units::isq::si::international; + + using distance = length; + using duration = isq::si::time; + + constexpr distance km = 1.0_q_km; + constexpr distance miles = 1.0_q_mi; + + constexpr duration sec = 1_q_s; + constexpr duration min = 1_q_min; + constexpr duration hr = 1_q_h; + + std::cout << "A physical quantities library can choose the simple\n"; + std::cout << "option to provide output using a single type for each base unit:\n\n"; + std::cout << km << '\n'; + std::cout << miles << '\n'; + std::cout << sec << '\n'; + std::cout << min << '\n'; + std::cout << hr << "\n\n"; +} + +void quantities_with_typed_units() +{ + using namespace units::isq; + using namespace units::isq::si; + using namespace units::isq::si::international; + + constexpr length km = 1.0_q_km; + constexpr length miles = 1.0_q_mi; + + std::cout.precision(6); + + constexpr si::time sec = 1_q_s; + constexpr si::time min = 1_q_min; + constexpr si::time hr = 1_q_h; + + std::cout << "A more flexible option is to provide separate types for each unit,\n\n"; + std::cout << km << '\n'; + std::cout << miles << '\n'; + std::cout << sec << '\n'; + std::cout << min << '\n'; + std::cout << hr << "\n\n"; + + constexpr length meter = 1_q_m; + std::cout << "then a wide range of pre-defined units can be defined and converted,\n" + " for consistency and repeatability across applications:\n\n"; + + std::cout << meter << '\n'; + + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; + std::cout << " = " << quantity_cast(meter) << '\n'; +} + +void calcs_comparison() +{ + using namespace units::isq::si; + + std::cout << "\nA distinct unit for each type is efficient and accurate\n" + "when adding two values of the same very big\n" + "or very small type:\n\n"; + + length L1A = 2._q_fm; + length L2A = 3._q_fm; + length LrA = L1A + L2A; + fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); + + std::cout << "The single unit method must convert large\n" + "or small values in other units to the base unit.\n" + "This is both inefficient and inaccurate\n\n"; + + length L1B = L1A; + length L2B = L2A; + length LrB = L1B + L2B; + fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); + + std::cout << "In multiplication and division:\n\n"; + + area ArA = L1A * L2A; + fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); + + std::cout << "similar problems arise\n\n"; + + area ArB = L1B * L2B; + fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); +} + +} // namespace + +int main() +{ + std::cout << "This demo was originally posted on com.lang.c++.moderated in 2006\n"; + std::cout << "http://compgroups.net/comp.lang.c++.moderated/dimensional-analysis-units/51712\n"; + std::cout << "Here converted to use mp-units library.\n\n"; + + simple_quantities(); + quantities_with_typed_units(); + calcs_comparison(); +} diff --git a/example/literals/conversion_factor.cpp b/example/literals/conversion_factor.cpp new file mode 100644 index 00000000..7e370522 --- /dev/null +++ b/example/literals/conversion_factor.cpp @@ -0,0 +1,60 @@ +/* + Copyright (c) 2003-2020 Andy Little. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses./ +*/ + +#include +#include +#include +#include + +/* + get conversion factor from one dimensionally equivalent + quantity type to another +*/ + +namespace { + +template + requires units::equivalent +inline constexpr std::common_type_t conversion_factor(Target, Source) +{ + // get quantities looking like inputs but with Q::rep that doesn't have narrowing conversion + typedef std::common_type_t rep; + typedef units::quantity source; + typedef units::quantity target; + return target{source{1}}.number(); +} + +} // namespace + +int main() +{ + using namespace units::isq::si; + + std::cout << "conversion factor in mp-units...\n\n"; + + constexpr length lengthA = 2.0_q_m; + constexpr length lengthB = lengthA; + + std::cout << fmt::format("lengthA( {} ) and lengthB( {} )\n", lengthA, lengthB) + << "represent the same length in different units.\n\n"; + + std::cout << fmt::format("therefore ratio lengthA / lengthB == {}\n\n", lengthA / lengthB); + + std::cout << fmt::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n", lengthA, lengthB) + << fmt::format("lengthB.number( {} ) == lengthA.number( {} ) * conversion_factor( {} )\n", + lengthB.number(), lengthA.number(), conversion_factor(lengthB, lengthA)); +} diff --git a/example/custom_systems.cpp b/example/literals/custom_systems.cpp similarity index 100% rename from example/custom_systems.cpp rename to example/literals/custom_systems.cpp diff --git a/example/literals/experimental_angle.cpp b/example/literals/experimental_angle.cpp new file mode 100644 index 00000000..4a4d0468 --- /dev/null +++ b/example/literals/experimental_angle.cpp @@ -0,0 +1,44 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +#include + +int main() +{ + using namespace units::literals; + using namespace units::isq; + using namespace units::isq::si::literals; + + Torque auto torque = 20.0_q_Nm_per_rad; + Energy auto energy = 20.0_q_J; + + units::Angle auto angle = energy / torque; + + std::cout << angle << '\n'; +} diff --git a/example/literals/foot_pound_second.cpp b/example/literals/foot_pound_second.cpp new file mode 100644 index 00000000..841068f7 --- /dev/null +++ b/example/literals/foot_pound_second.cpp @@ -0,0 +1,99 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace units::isq; + + +// Some basic specs for the warship +struct Ship { + si::fps::length length; + si::fps::length draft; + si::fps::length beam; + + si::fps::speed speed; + si::fps::mass mass; + + si::fps::length mainGuns; + si::fps::mass shellMass; + si::fps::speed shellSpeed; + si::fps::power power; +}; + +// Print 'a' in its current units and print its value cast to the units in each of Args +template +auto fmt_line(const Q a) +{ + return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast(a)) + ...); +} + +// Print the ship details in the units as defined in the Ship struct, in other si::imperial units, and in SI +void print_details(std::string_view description, const Ship& ship) +{ + using namespace units::isq::si::fps::literals; + const auto waterDensity = 62.4_q_lb_per_ft3; + std::cout << fmt::format("{}\n", description); + std::cout << fmt::format("{:20} : {}\n", "length", fmt_line, si::length>(ship.length)) + << fmt::format("{:20} : {}\n", "draft", fmt_line, si::length>(ship.draft)) + << fmt::format("{:20} : {}\n", "beam", fmt_line, si::length>(ship.beam)) + << fmt::format("{:20} : {}\n", "mass", fmt_line, si::mass>(ship.mass)) + << fmt::format("{:20} : {}\n", "speed", fmt_line, si::speed>(ship.speed)) + << fmt::format("{:20} : {}\n", "power", fmt_line, si::power>(ship.power)) + << fmt::format("{:20} : {}\n", "main guns", fmt_line, si::length>(ship.mainGuns)) + << fmt::format("{:20} : {}\n", "fire shells weighing",fmt_line, si::mass>(ship.shellMass)) + << fmt::format("{:20} : {}\n", "fire shells at",fmt_line, si::speed>(ship.shellSpeed)) + << fmt::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume>(ship.mass / waterDensity)); +} + +int main() +{ + using namespace units::isq::si::literals; + using namespace units::isq::si::fps::literals; + + // KMS Bismark, using the units the Germans would use, taken from Wiki + auto bismark = Ship{.length{251._q_m}, .draft{9.3_q_m}, .beam{36_q_m}, .speed{56_q_km_per_h}, .mass{50'300_q_t}, .mainGuns{380_q_mm}, .shellMass{800_q_kg}, .shellSpeed{820._q_m_per_s}, .power{110.45_q_kW}}; + + // USS Iowa, using units from the foot-pound-second system + auto iowa = Ship{.length{860._q_ft}, .draft{37._q_ft + 2._q_in}, .beam{108._q_ft + 2._q_in}, .speed{33_q_knot}, .mass{57'540_q_lton}, .mainGuns{16_q_in}, .shellMass{2700_q_lb}, .shellSpeed{2690._q_ft_per_s}, .power{212'000_q_hp}}; + + // HMS King George V, using units from the foot-pound-second system + auto kgv = Ship{.length{745.1_q_ft}, .draft{33._q_ft + 7.5_q_in}, .beam{103.2_q_ft + 2.5_q_in}, .speed{28.3_q_knot}, .mass{42'245_q_lton}, .mainGuns{14_q_in}, .shellMass{1'590_q_lb}, .shellSpeed{2483._q_ft_per_s}, .power{110'000_q_hp}}; + + print_details("KMS Bismark, defined in appropriate units from the SI system", bismark); + std::cout << "\n\n"; + print_details("USS Iowa, defined in appropriate units foot-pound-second system", iowa); + std::cout << "\n\n"; + print_details("HMS King George V, defined in appropriate units foot-pound-second system", kgv); +} diff --git a/example/literals/geographic.cpp b/example/literals/geographic.cpp new file mode 100644 index 00000000..2e8b7576 --- /dev/null +++ b/example/literals/geographic.cpp @@ -0,0 +1,63 @@ +// 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. + +#include "geographic.h" +#include +#include +#include + +namespace { + +using namespace units::isq::si::literals; +inline constexpr auto earth_radius = 6371._q_km; + +} // namespace + +namespace geographic { + +distance spherical_distance(position from, position to) +{ + using rep = std::common_type_t; + constexpr auto p = std::numbers::pi_v / 180; + const auto lat1 = from.lat.value() * p; + const auto lon1 = from.lon.value() * p; + const auto lat2 = to.lat.value() * p; + const auto lon2 = to.lon.value() * p; + + using std::sin, std::cos, std::asin, std::sqrt; + + // https://en.wikipedia.org/wiki/Great-circle_distance#Formulae + if constexpr (sizeof(rep) >= 8) { + // spherical law of cosines + const auto central_angle = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)); + // const auto central_angle = 2 * asin(sqrt(0.5 - cos(lat2 - lat1) / 2 + cos(lat1) * cos(lat2) * (1 - cos(lon2 - lon1)) / 2)); + return distance(earth_radius * central_angle); + } else { + // the haversine formula + const auto sin_lat = sin(lat2 - lat1) / 2; + const auto sin_lon = sin(lon2 - lon1) / 2; + const auto central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(lat1) * cos(lat2) * sin_lon * sin_lon)); + return distance(earth_radius * central_angle); + } +} + +} // namespace geographic diff --git a/example/literals/geographic.h b/example/literals/geographic.h new file mode 100644 index 00000000..430e1fbb --- /dev/null +++ b/example/literals/geographic.h @@ -0,0 +1,139 @@ +// 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 + +UNITS_DIAGNOSTIC_PUSH +UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE +#include +UNITS_DIAGNOSTIC_POP + +#include +#include + +// IWYU pragma: begin_exports +#include +// IWYU pragma: end_exports + +namespace geographic { + +template +struct coordinate { + using value_type = Rep; + constexpr explicit coordinate(value_type v) : value_(v) {} + value_type value() const { return value_; } + auto operator<=>(const coordinate&) const = default; +private: + value_type value_; +}; + +struct latitude : coordinate { + using coordinate::coordinate; +}; + +struct longitude : coordinate { + using coordinate::coordinate; +}; + +template +std::basic_ostream& operator<<(std::basic_ostream& os, const latitude& lat) +{ + if (lat.value() > 0) + return os << "N" << lat.value(); + else + return os << "S" << -lat.value(); +} + +template +std::basic_ostream& operator<<(std::basic_ostream& os, const longitude& lon) +{ + if (lon.value() > 0) + return os << "E" << lon.value(); + else + return os << "W" << -lon.value(); +} + +inline namespace literals { + +constexpr auto operator"" _N(unsigned long long v) { return latitude(static_cast(v)); } +constexpr auto operator"" _N(long double v) { return latitude(static_cast(v)); } +constexpr auto operator"" _S(unsigned long long v) { return latitude(-static_cast(v)); } +constexpr auto operator"" _S(long double v) { return latitude(-static_cast(v)); } +constexpr auto operator"" _E(unsigned long long v) { return longitude(static_cast(v)); } +constexpr auto operator"" _E(long double v) { return longitude(static_cast(v)); } +constexpr auto operator"" _W(unsigned long long v) { return longitude(-static_cast(v)); } +constexpr auto operator"" _W(long double v) { return longitude(-static_cast(v)); } + +} // namespace literals + +} // namespace geographic + +template<> +class std::numeric_limits : public numeric_limits { + static constexpr auto min() noexcept { return geographic::latitude(-90); } + static constexpr auto lowest() noexcept { return geographic::latitude(-90); } + static constexpr auto max() noexcept { return geographic::latitude(90); } +}; + +template<> +class std::numeric_limits : public numeric_limits { + static constexpr auto min() noexcept { return geographic::longitude(-180); } + static constexpr auto lowest() noexcept { return geographic::longitude(-180); } + static constexpr auto max() noexcept { return geographic::longitude(180); } +}; + +template<> +struct fmt::formatter : formatter { + template + auto format(geographic::latitude lat, FormatContext& ctx) + { + format_to(ctx.out(), lat.value() > 0 ? "N" : "S"); + return formatter::format(lat.value() > 0 ? lat.value() : -lat.value(), ctx); + } +}; + +template<> +struct fmt::formatter : formatter { + template + auto format(geographic::longitude lon, FormatContext& ctx) + { + format_to(ctx.out(), lon.value() > 0 ? "E" : "W"); + return formatter::format(lon.value() > 0 ? lon.value() : -lon.value(), ctx); + } +}; + +namespace geographic { + +struct horizontal_kind : units::kind {}; +using distance = units::quantity_kind; + +struct position { + latitude lat; + longitude lon; +}; + +distance spherical_distance(position from, position to); + +} // namespace geographic diff --git a/example/glide_computer.cpp b/example/literals/glide_computer.cpp similarity index 100% rename from example/glide_computer.cpp rename to example/literals/glide_computer.cpp diff --git a/example/glide_computer.h b/example/literals/glide_computer.h similarity index 100% rename from example/glide_computer.h rename to example/literals/glide_computer.h diff --git a/example/literals/glide_computer_example.cpp b/example/literals/glide_computer_example.cpp new file mode 100644 index 00000000..ae63734c --- /dev/null +++ b/example/literals/glide_computer_example.cpp @@ -0,0 +1,202 @@ +// 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. + +#include "glide_computer.h" +#include +#include +#include +#include + +UNITS_DIAGNOSTIC_PUSH +UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE +#include +UNITS_DIAGNOSTIC_POP + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using namespace glide_computer; + +using namespace units::isq; + +auto get_gliders() +{ + using namespace si::literals; +UNITS_DIAGNOSTIC_PUSH +UNITS_DIAGNOSTIC_IGNORE_MISSING_BRACES + static const std::array gliders = { + glider{"SZD-30 Pirat", {velocity(83_q_km_per_h), rate_of_climb(-0.7389_q_m_per_s)}}, + glider{"SZD-51 Junior", {velocity(80_q_km_per_h), rate_of_climb(-0.6349_q_m_per_s)}}, + glider{"SZD-48 Jantar Std 3", {velocity(110_q_km_per_h), rate_of_climb(-0.77355_q_m_per_s)}}, + glider{"SZD-56 Diana", {velocity(110_q_km_per_h), rate_of_climb(-0.63657_q_m_per_s)}}}; +UNITS_DIAGNOSTIC_POP + return gliders; +} + +auto get_weather_conditions() +{ + using namespace si::literals; + static const std::array weather_conditions = { + std::pair("Good", weather{height(1900_q_m), rate_of_climb(4.3_q_m_per_s)}), + std::pair("Medium", weather{height(1550_q_m), rate_of_climb(2.8_q_m_per_s)}), + std::pair("Bad", weather{height(850_q_m), rate_of_climb(1.8_q_m_per_s)})}; + return weather_conditions; +} + +auto get_waypoints() +{ + using namespace geographic::literals; + using namespace units::isq::si::international::literals; + static const std::array waypoints = { + waypoint{"EPPR", {54.24772_N, 18.6745_E}, altitude(16_q_ft)}, // N54°14'51.8" E18°40'28.2" + waypoint{"EPGI", {53.52442_N, 18.84947_E}, altitude(115_q_ft)} // N53°31'27.9" E18°50'58.1" + }; + return waypoints; +} + +template + requires std::same_as, glider> +void print(const R& gliders) +{ + std::cout << "Gliders:\n"; + std::cout << "========\n"; + for (const auto& g : gliders) { + std::cout << "- Name: " << g.name << "\n"; + std::cout << "- Polar:\n"; + for (const auto& p : g.polar) + fmt::print(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); + std::cout << "\n"; + } +} + +template + requires std::same_as, std::pair> +void print(const R& conditions) +{ + std::cout << "Weather:\n"; + std::cout << "========\n"; + for (const auto& c : conditions) { + std::cout << "- " << c.first << "\n"; + const auto& w = c.second; + std::cout << " * Cloud base: " << fmt::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; + std::cout << " * Thermals strength: " << fmt::format("{:%.1Q %q}", w.thermal_strength) << "\n"; + std::cout << "\n"; + } +} + +template + requires std::same_as, waypoint> +void print(const R& waypoints) +{ + std::cout << "Waypoints:\n"; + std::cout << "==========\n"; + for (const auto& w : waypoints) + std::cout << fmt::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); + std::cout << "\n"; +} + +void print(const task& t) +{ + std::cout << "Task:\n"; + std::cout << "=====\n"; + + std::cout << "- Start: " << t.get_start().name << "\n"; + std::cout << "- Finish: " << t.get_finish().name << "\n"; + std::cout << "- Length: " << fmt::format("{:%.1Q %q}", t.get_length()) << "\n"; + + std::cout << "- Legs: " << "\n"; + for (const auto& l : t.get_legs()) + std::cout << fmt::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); + std::cout << "\n"; +} + +void print(const safety& s) +{ + std::cout << "Safety:\n"; + std::cout << "=======\n"; + std::cout << "- Min AGL separation: " << fmt::format("{:%.0Q %q}", s.min_agl_height) << "\n"; + std::cout << "\n"; +} + +void print(const aircraft_tow& tow) +{ + std::cout << "Tow:\n"; + std::cout << "====\n"; + std::cout << "- Type: aircraft\n"; + std::cout << "- Height: " << fmt::format("{:%.0Q %q}", tow.height_agl) << "\n"; + std::cout << "- Performance: " << fmt::format("{:%.1Q %q}", tow.performance) << "\n"; + std::cout << "\n"; +} + +void example() +{ + using namespace si::literals; + + const safety sfty = {height(300_q_m)}; + const auto gliders = get_gliders(); + const auto waypoints = get_waypoints(); + const auto weather_conditions = get_weather_conditions(); + const task t = {waypoints[0], waypoints[1], waypoints[0]}; + const aircraft_tow tow = {height(400_q_m), rate_of_climb(1.6_q_m_per_s)}; + // TODO use C++20 date library when available + // set `start_time` to 11:00 am today + const timestamp start_time(std::chrono::system_clock::now()); + + print(sfty); + print(gliders); + print(waypoints); + print(weather_conditions); + print(t); + print(tow); + + for (const auto& g : gliders) { + for (const auto& c : weather_conditions) { + std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first; + std::cout << txt << "\n"; + fmt::print("{0:=^{1}}\n\n", "", txt.size()); + + estimate(start_time, g, c.second, t, sfty, tow); + + std::cout << "\n\n"; + } + } +} + +} // namespace + +int main() +{ + try { + example(); + } catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/literals/kalman_filter-alpha_beta_filter_example2.cpp b/example/literals/kalman_filter-alpha_beta_filter_example2.cpp new file mode 100644 index 00000000..52f53ead --- /dev/null +++ b/example/literals/kalman_filter-alpha_beta_filter_example2.cpp @@ -0,0 +1,100 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +/* + kalman filter tutorial + 1d aircraft α-β filter example2 from https://www.kalmanfilter.net/alphabeta.html#ex2 +*/ + +namespace { + +template +struct state_variable { + Q estimated_current_state; + Q predicted_next_state; +}; + +using namespace units::isq; +using namespace units::isq::si::literals; + +constexpr auto radar_transmit_interval = 5.0_q_s; +constexpr double kalman_range_gain = 0.2; +constexpr double kalman_speed_gain = 0.1; + +struct state { + state_variable> range; + state_variable> speed; + + constexpr void estimate(const state& previous_state, const si::length& measurement) + { + auto const innovation = measurement - previous_state.range.predicted_next_state; + range.estimated_current_state = previous_state.range.predicted_next_state + kalman_range_gain * innovation; + speed.estimated_current_state = + previous_state.speed.predicted_next_state + kalman_speed_gain * innovation / radar_transmit_interval; + } + + constexpr void predict() + { + range.predicted_next_state = + range.estimated_current_state + speed.estimated_current_state * radar_transmit_interval; + speed.predicted_next_state = speed.estimated_current_state; + } +}; + +} // namespace + +int main() +{ + std::cout << "\n\n1d aircraft α-β filter example2 from https://www.kalmanfilter.net/alphabeta.html#ex2"; + std::cout << "\n\n"; + + constexpr auto measurements = std::array{0.0_q_m, // N.B measurement[0] is unknown and unused + 30110.0_q_m, 30265.0_q_m, 30740.0_q_m, 30750.0_q_m, 31135.0_q_m, + 31015.0_q_m, 31180.0_q_m, 31610.0_q_m, 31960.0_q_m, 31865.0_q_m}; + + constexpr auto num_measurements = measurements.size(); + + std::array track; + // We need an initial estimate of track[0] as there is no previous state to get a prediction from + track[0].range.estimated_current_state = 30'000_q_m; + track[0].speed.estimated_current_state = 40.0_q_m_per_s; + + for (auto n = 0U; n < num_measurements; ++n) { + if (n > 0) { + track[n].estimate(track[n - 1], measurements[n]); + } + track[n].predict(); + + std::cout << fmt::format("measurement[{}] = {:.0}\n", n, measurements[n]); + std::cout << fmt::format("range.estimated_current_state[{}] = {:.1}\n", n, track[n].range.estimated_current_state); + std::cout << fmt::format("speed.estimated_current_state[{}] = {:.1}\n", n, track[n].speed.estimated_current_state); + std::cout << fmt::format("range.predicted_next_state[{}] = {:.1}\n", n, track[n].range.predicted_next_state); + std::cout << fmt::format("speed.predicted_next_state[{}] = {:.1}\n\n", n, track[n].speed.predicted_next_state); + } +} diff --git a/example/literals/linear_algebra.cpp b/example/literals/linear_algebra.cpp new file mode 100644 index 00000000..e98b69bd --- /dev/null +++ b/example/literals/linear_algebra.cpp @@ -0,0 +1,361 @@ +// 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. + +#include // IWYU pragma: keep +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include + +namespace STD_LA { + +template +std::ostream& operator<<(std::ostream& os, const vector& v) +{ + os << "|"; + for (auto i = 0U; i < v.size(); ++i) { + os << fmt::format(" {:>9}", v(i)); + } + os << " |"; + return os; +} + +template +std::ostream& operator<<(std::ostream& os, const matrix& v) +{ + for (auto i = 0U; i < v.rows(); ++i) { + os << "|"; + for (auto j = 0U; j < v.columns(); ++j) { + os << fmt::format(" {:>9}", v(i, j)); + } + os << (i != v.rows() - 1U ? " |\n" : " |"); + } + return os; +} + +} // namespace STD_LA + +namespace { + +using namespace units::isq; +using namespace units::isq::si::literals; + +template +using vector = std::math::fs_vector; + +template +using matrix = std::math::fs_matrix; + + +void vector_of_quantity_add() +{ + std::cout << "\nvector_of_quantity_add:\n"; + + vector> v = { 1_q_m, 2_q_m, 3_q_m }; + vector> u = { 3_q_m, 2_q_m, 1_q_m }; + vector> t = { 3_q_km, 2_q_km, 1_q_km }; + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + std::cout << "t = " << t << "\n"; + + std::cout << "v + u = " << v + u << "\n"; + std::cout << "v + t = " << v + t << "\n"; + std::cout << "t[m] = " << vector>(t) << "\n"; +} + +void vector_of_quantity_multiply_same() +{ + std::cout << "\nvector_of_quantity_multiply_same:\n"; + + vector> v = { 1_q_m, 2_q_m, 3_q_m }; + vector> u = { 3_q_m, 2_q_m, 1_q_m }; + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + + std::cout << "v * u = " << v * u << "\n"; + std::cout << "2_q_m * v = " << 2._q_m * v << "\n"; +} + +void vector_of_quantity_multiply_different() +{ + std::cout << "\nvector_of_quantity_multiply_different:\n"; + + vector> v = { 1_q_N, 2_q_N, 3_q_N }; + vector> u = { 3_q_m, 2_q_m, 1_q_m }; + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + + std::cout << "v * u = " << v * u << "\n"; + std::cout << "2_q_N * u = " << 2._q_N * u << "\n"; + std::cout << "2 * u = " << 2 * u << "\n"; +} + +void vector_of_quantity_divide_by_scalar() +{ + std::cout << "\nvector_of_quantity_divide_by_scalar:\n"; + + vector> v = { 4_q_m, 8_q_m, 12_q_m }; + + std::cout << "v = " << v << "\n"; + + // TODO Uncomment when bug in the LA is fixed + // std::cout << "v / 2_q_s = " << v / 2_q_s << "\n"; + // std::cout << "v / 2 = " << v / 2 << "\n"; +} + +void vector_of_quantity_tests() +{ + vector_of_quantity_add(); + vector_of_quantity_multiply_same(); + vector_of_quantity_multiply_different(); + vector_of_quantity_divide_by_scalar(); +} + +void matrix_of_quantity_add() +{ + std::cout << "\nmatrix_of_quantity_add:\n"; + + matrix> v = {{ 1_q_m, 2_q_m, 3_q_m }, { 4_q_m, 5_q_m, 6_q_m }, { 7_q_m, 8_q_m, 9_q_m }}; + matrix> u = {{ 3_q_m, 2_q_m, 1_q_m }, { 3_q_m, 2_q_m, 1_q_m }, { 3_q_m, 2_q_m, 1_q_m }}; + matrix> t = {{ 3_q_mm, 2_q_mm, 1_q_mm }, { 3_q_mm, 2_q_mm, 1_q_mm }, { 3_q_mm, 2_q_mm, 1_q_mm }}; + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + std::cout << "t =\n" << t << "\n"; + + std::cout << "v + u =\n" << v + u << "\n"; + std::cout << "v + t =\n" << v + t << "\n"; + + // TODO Uncomment when fixed in the LA lib + // std::cout << "v[mm] =\n" << matrix>(v) << "\n"; +} + +void matrix_of_quantity_multiply_same() +{ + std::cout << "\nmatrix_of_quantity_multiply_same:\n"; + + matrix> v = {{ 1_q_m, 2_q_m, 3_q_m }, { 4_q_m, 5_q_m, 6_q_m }, { 7_q_m, 8_q_m, 9_q_m }}; + vector> u = { 3_q_m, 2_q_m, 1_q_m }; + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + + std::cout << "v * u =\n" << v * u << "\n"; + std::cout << "2_q_m * u =\n" << 2._q_m * u << "\n"; +} + +void matrix_of_quantity_multiply_different() +{ + std::cout << "\nmatrix_of_quantity_multiply_different:\n"; + + vector> v = { 1_q_N, 2_q_N, 3_q_N }; + matrix> u = {{ 1_q_m, 2_q_m, 3_q_m }, { 4_q_m, 5_q_m, 6_q_m }, { 7_q_m, 8_q_m, 9_q_m }}; + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + + std::cout << "v * u =\n" << v * u << "\n"; + std::cout << "2_q_N * u =\n" << 2._q_N * u << "\n"; + std::cout << "2 * u =\n" << 2 * u << "\n"; +} + +void matrix_of_quantity_divide_by_scalar() +{ + std::cout << "\nmatrix_of_quantity_divide_by_scalar:\n"; + + matrix> v = {{ 2_q_m, 4_q_m, 6_q_m }, { 4_q_m, 6_q_m, 8_q_m }, { 8_q_m, 4_q_m, 2_q_m }}; + + std::cout << "v =\n" << v << "\n"; + + // TODO Uncomment when bug in the LA is fixed + // std::cout << "v / 2_q_s =\n" << v / 2_q_s << "\n"; + // std::cout << "v / 2 =\n" << v / 2 << "\n"; +} + +void matrix_of_quantity_tests() +{ + matrix_of_quantity_add(); + matrix_of_quantity_multiply_same(); + matrix_of_quantity_multiply_different(); + matrix_of_quantity_divide_by_scalar(); +} + +template +using length_v = si::length>; + +template +using force_v = si::force>; + +void quantity_of_vector_add() +{ + std::cout << "\nquantity_of_vector_add:\n"; + + length_v<> v(vector<>{ 1, 2, 3 }); + length_v<> u(vector<>{ 3, 2, 1 }); + length_v t(vector<>{ 3, 2, 1 }); + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + std::cout << "t = " << t << "\n"; + + std::cout << "v + u = " << v + u << "\n"; + std::cout << "v + t = " << v + t << "\n"; + std::cout << "t[m] = " << quantity_cast(t) << "\n"; +} + +void quantity_of_vector_multiply_same() +{ + std::cout << "\nquantity_of_vector_multiply_same:\n"; + + length_v<> v(vector<>{ 1, 2, 3 }); + length_v<> u(vector<>{ 3, 2, 1 }); + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + + std::cout << "v * u = " << v * u << "\n"; + std::cout << "2_q_m * v = " << 2._q_m * v << "\n"; +} + +void quantity_of_vector_multiply_different() +{ + std::cout << "\nquantity_of_vector_multiply_different:\n"; + + force_v<> v(vector<>{ 1, 2, 3 }); + length_v<> u(vector<>{ 3, 2, 1 }); + + std::cout << "v = " << v << "\n"; + std::cout << "u = " << u << "\n"; + + std::cout << "v * u = " << v * u << "\n"; + std::cout << "2_q_N * u = " << 2._q_N * u << "\n"; + std::cout << "2 * u = " << 2 * u << "\n"; +} + +void quantity_of_vector_divide_by_scalar() +{ + std::cout << "\nquantity_of_vector_divide_by_scalar:\n"; + + length_v<> v(vector<>{ 4, 8, 12 }); + + std::cout << "v = " << v << "\n"; + + // TODO Uncomment when bug in the LA is fixed + // std::cout << "v / 2_q_s = " << v / 2_q_s << "\n"; + // std::cout << "v / 2 = " << v / 2 << "\n"; +} + +void quantity_of_vector_tests() +{ + quantity_of_vector_add(); + quantity_of_vector_multiply_same(); + quantity_of_vector_multiply_different(); + quantity_of_vector_divide_by_scalar(); +} + +template +using length_m = si::length>; + +void quantity_of_matrix_add() +{ + std::cout << "\nquantity_of_matrix_add:\n"; + + length_m<> v(matrix<>{{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }}); + length_m<> u(matrix<>{{ 3, 2, 1 }, { 3, 2, 1 }, { 3, 2, 1 }}); + length_m t(matrix<>{{ 3, 2, 1 }, { 3, 2, 1 }, { 3, 2, 1 }}); + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + std::cout << "t =\n" << t << "\n"; + + std::cout << "v + u =\n" << v + u << "\n"; + std::cout << "v + t =\n" << v + t << "\n"; + + // TODO Uncomment when fixed in the LA lib + // std::cout << "v[mm] =\n" << matrix>(v) << "\n"; +} + +void quantity_of_matrix_multiply_same() +{ + std::cout << "\nquantity_of_matrix_multiply_same:\n"; + + length_m<> v(matrix<>{{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }}); + length_v<> u(vector<>{ 3, 2, 1 }); + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + + std::cout << "v * u =\n" << v * u << "\n"; + std::cout << "2_q_m * u =\n" << 2._q_m * u << "\n"; +} + +void quantity_of_matrix_multiply_different() +{ + std::cout << "\nquantity_of_matrix_multiply_different:\n"; + + force_v<> v(vector<>{ 1, 2, 3 }); + length_m<> u(matrix<>{{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }}); + + std::cout << "v =\n" << v << "\n"; + std::cout << "u =\n" << u << "\n"; + + std::cout << "v * u =\n" << v * u << "\n"; + std::cout << "2_q_N * u =\n" << 2._q_N * u << "\n"; + std::cout << "2 * u =\n" << 2 * u << "\n"; +} + +void quantity_of_matrix_divide_by_scalar() +{ + std::cout << "\nquantity_of_matrix_divide_by_scalar:\n"; + + length_m<> v(matrix<>{{ 2, 4, 6 }, { 4, 6, 8 }, { 8, 4, 2 }}); + + std::cout << "v =\n" << v << "\n"; + + // TODO Uncomment when bug in the LA is fixed + // std::cout << "v / 2_q_s =\n" << v / 2_q_s << "\n"; + // std::cout << "v / 2 =\n" << v / 2 << "\n"; +} + +void quantity_of_matrix_tests() +{ + quantity_of_matrix_add(); + quantity_of_matrix_multiply_same(); + quantity_of_matrix_multiply_different(); + quantity_of_matrix_divide_by_scalar(); +} + +} // namespace + +int main() +{ + vector_of_quantity_tests(); + matrix_of_quantity_tests(); + quantity_of_vector_tests(); + quantity_of_matrix_tests(); +} diff --git a/example/measurement.cpp b/example/literals/measurement.cpp similarity index 100% rename from example/measurement.cpp rename to example/literals/measurement.cpp diff --git a/example/literals/total_energy.cpp b/example/literals/total_energy.cpp new file mode 100644 index 00000000..7420f241 --- /dev/null +++ b/example/literals/total_energy.cpp @@ -0,0 +1,104 @@ +// 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. + +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include + +namespace { + +using namespace units::isq; + +Energy auto total_energy(Momentum auto p, Mass auto m, Speed auto c) +{ + return sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c))); +} + +void si_example() +{ + using namespace units::isq::si; + using GeV = gigaelectronvolt; + + constexpr Speed auto c = si2019::speed_of_light<>; + + std::cout << "\n*** SI units (c = " << c << ") ***\n"; + + const Momentum auto p = 4._q_GeV / c; + const Mass auto m = 3._q_GeV / pow<2>(c); + const Energy auto E = total_energy(p, m, c); + + std::cout << "[in GeV]\n" + << "p = " << p << "\n" + << "m = " << m << "\n" + << "E = " << E << "\n"; + + const momentum p_si = p; + const mass m_si = m; + const energy E_si = total_energy(p_si, m_si, c); + + std::cout << "\n[in SI units]\n" + << "p = " << p_si << "\n" + << "m = " << m_si << "\n" + << "E = " << E_si << "\n"; + + std::cout << "\n[converted from SI units back to GeV]\n" + << "E = " << quantity_cast(E_si) << "\n"; +} + +void natural_example() +{ + using namespace units::isq::natural; + using GeV = gigaelectronvolt; + + constexpr Speed auto c = speed_of_light<>; + const momentum p(4); + const mass m(3); + const Energy auto E = total_energy(p, m, c); + + std::cout << "\n*** Natural units (c = " << c << ") ***\n" + << "p = " << p << "\n" + << "m = " << m << "\n" + << "E = " << E << "\n"; +} + +} // namespace + +int main() +{ + try { + si_example(); + natural_example(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/literals/unknown_dimension.cpp b/example/literals/unknown_dimension.cpp new file mode 100644 index 00000000..aed204d8 --- /dev/null +++ b/example/literals/unknown_dimension.cpp @@ -0,0 +1,72 @@ +// 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. + +#include +#include // IWYU pragma: keep +#include +#include +#include +#include + +namespace { + +template +constexpr units::isq::Speed auto avg_speed(D d, T t) +{ + return d / t; +} + +void example() +{ + using namespace units::isq; + using namespace units::isq::si::literals; + + Length auto d1 = 123_q_m; + Time auto t1 = 10_q_s; + Speed auto v1 = avg_speed(d1, t1); + + auto temp1 = v1 * 50_q_m; // produces intermediate unknown dimension with 'unknown_coherent_unit' as its 'coherent_unit' + Speed auto v2 = temp1 / 100_q_m; // back to known dimensions again + Length auto d2 = v2 * 60_q_s; + + std::cout << "d1 = " << d1 << '\n'; + std::cout << "t1 = " << t1 << '\n'; + std::cout << "v1 = " << v1 << '\n'; + std::cout << "temp1 = " << temp1 << '\n'; + std::cout << "v2 = " << v2 << '\n'; + std::cout << "d2 = " << d2 << '\n'; +} + +} // namespace + +int main() +{ + try { + example(); + } + catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } + catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/references/CMakeLists.txt b/example/references/CMakeLists.txt new file mode 100644 index 00000000..8a4d69bf --- /dev/null +++ b/example/references/CMakeLists.txt @@ -0,0 +1,60 @@ +# 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.2) + +# +# add_example(target ...) +# +function(add_example target) + add_executable(${target}-references ${target}.cpp) + target_link_libraries(${target}-references PRIVATE ${ARGN}) + target_compile_definitions(${target}-references PRIVATE UNITS_REFERENCES) +endfunction() + +add_example(avg_speed mp-units::core-io mp-units::si mp-units::si-cgs mp-units::si-international) +add_example(box_example mp-units::core-fmt mp-units::si) +add_example(capacitor_time_curve mp-units::core-io mp-units::si) +add_example(clcpp_response mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-iau mp-units::si-imperial mp-units::si-international mp-units::si-typographic mp-units::si-us) +add_example(conversion_factor mp-units::core-fmt mp-units::core-io mp-units::si) +add_example(custom_systems mp-units::core-io mp-units::si) +add_example(experimental_angle mp-units::core-fmt mp-units::core-io mp-units::si) +add_example(foot_pound_second mp-units::core-fmt mp-units::si-fps) +add_example(kalman_filter-alpha_beta_filter_example2 mp-units::core-fmt mp-units::si) +add_example(measurement mp-units::core-io mp-units::si) +add_example(total_energy mp-units::core-io mp-units::si mp-units::isq-natural) +add_example(unknown_dimension mp-units::core-io mp-units::si) + +if(NOT UNITS_LIBCXX) + add_executable(glide_computer-references + geographic.cpp geographic.h + glide_computer.cpp glide_computer.h + glide_computer_example.cpp + ) + target_link_libraries(glide_computer-references PRIVATE mp-units::core-fmt mp-units::si mp-units::si-international) + target_include_directories(glide_computer-references PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + target_compile_definitions(glide_computer-references PRIVATE UNITS_REFERENCES) + + find_package(linear_algebra CONFIG REQUIRED) + add_example(linear_algebra mp-units::core-fmt mp-units::core-io mp-units::si) + target_link_libraries(linear_algebra-references PRIVATE linear_algebra::linear_algebra) +endif() diff --git a/example/avg_speed.cpp b/example/references/avg_speed.cpp similarity index 100% rename from example/avg_speed.cpp rename to example/references/avg_speed.cpp diff --git a/example/box_example.cpp b/example/references/box_example.cpp similarity index 100% rename from example/box_example.cpp rename to example/references/box_example.cpp diff --git a/example/capacitor_time_curve.cpp b/example/references/capacitor_time_curve.cpp similarity index 100% rename from example/capacitor_time_curve.cpp rename to example/references/capacitor_time_curve.cpp diff --git a/example/clcpp_response.cpp b/example/references/clcpp_response.cpp similarity index 100% rename from example/clcpp_response.cpp rename to example/references/clcpp_response.cpp diff --git a/example/conversion_factor.cpp b/example/references/conversion_factor.cpp similarity index 100% rename from example/conversion_factor.cpp rename to example/references/conversion_factor.cpp diff --git a/example/references/custom_systems.cpp b/example/references/custom_systems.cpp new file mode 100644 index 00000000..f8fa8a3b --- /dev/null +++ b/example/references/custom_systems.cpp @@ -0,0 +1,113 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include + +using namespace units; + +namespace fps { + +struct foot : named_unit {}; +struct yard : named_scaled_unit {}; + +struct dim_length : base_dimension<"L", foot> {}; + +template U, Representation Rep = double> +using length = quantity; + +} // namespace fps + +namespace si { + +struct metre : named_unit {}; +struct kilometre : prefixed_unit {}; + +struct dim_length : base_dimension<"L", metre> {}; + +template U, Representation Rep = double> +using length = quantity; + +namespace fps { + +struct foot : named_scaled_unit {}; +struct yard : named_scaled_unit {}; + +struct dim_length : base_dimension<"L", foot> {}; + +template U, Representation Rep = double> +using length = quantity; + +} // namespace fps +} // namespace si + +void conversions() +{ + // constexpr auto fps_yard = fps::length(1.); + // std::cout << quantity_cast(fps_yard) << "\n"; + + constexpr auto si_fps_yard = si::fps::length(1.); + std::cout << quantity_cast(si_fps_yard) << "\n"; +} + +void unknown_dimensions() +{ + constexpr auto fps_yard = fps::length(1.); + constexpr auto fps_area = quantity_cast(fps_yard * fps_yard); + std::cout << fps_yard << "\n"; + std::cout << fps_area << "\n"; + + constexpr auto si_fps_yard = si::fps::length(1.); + constexpr auto si_fps_area = quantity_cast(si_fps_yard * si_fps_yard); + std::cout << si_fps_yard << "\n"; + std::cout << si_fps_area << "\n"; +} + +std::ostream& operator<<(std::ostream& os, const ratio& r) +{ + return os << "ratio{" << r.num << ", " << r.den << ", " << r.exp << "}"; +} + +template +std::ostream& operator<<(std::ostream& os, const U& u) +{ + using unit_type = std::remove_cvref_t; + return os << unit_type::ratio << " x " << unit_type::reference::symbol.standard(); +} + +void what_is_your_ratio() +{ + std::cout << "fps: " << fps::yard() << "\n"; + std::cout << "si::fps: " << si::fps::yard() << "\n"; +} + +int main() +{ + conversions(); + unknown_dimensions(); + what_is_your_ratio(); +} diff --git a/example/experimental_angle.cpp b/example/references/experimental_angle.cpp similarity index 100% rename from example/experimental_angle.cpp rename to example/references/experimental_angle.cpp diff --git a/example/foot_pound_second.cpp b/example/references/foot_pound_second.cpp similarity index 100% rename from example/foot_pound_second.cpp rename to example/references/foot_pound_second.cpp diff --git a/example/geographic.cpp b/example/references/geographic.cpp similarity index 100% rename from example/geographic.cpp rename to example/references/geographic.cpp diff --git a/example/geographic.h b/example/references/geographic.h similarity index 100% rename from example/geographic.h rename to example/references/geographic.h diff --git a/example/references/glide_computer.cpp b/example/references/glide_computer.cpp new file mode 100644 index 00000000..6325ca46 --- /dev/null +++ b/example/references/glide_computer.cpp @@ -0,0 +1,166 @@ +// 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. + +#include "glide_computer.h" +#include +#include + +namespace glide_computer { + +using namespace units::isq; + +task::legs task::make_legs(const waypoints& wpts) +{ + task::legs res; + res.reserve(wpts.size() - 1); + auto to_leg = [](const waypoint& w1, const waypoint& w2) { return task::leg(w1, w2); }; + std::ranges::transform(wpts.cbegin(), prev(wpts.cend()), next(wpts.cbegin()), wpts.cend(), std::back_inserter(res), to_leg); + return res; +} + +std::vector task::make_leg_total_distances(const legs& legs) +{ + std::vector res; + res.reserve(legs.size()); + auto to_length = [](const leg& l) { return l.get_length(); }; + std::transform_inclusive_scan(legs.cbegin(), legs.cend(), std::back_inserter(res), std::plus(), to_length); + return res; +} + +altitude terrain_level_alt(const task& t, const flight_point& pos) +{ + const task::leg& l = t.get_legs()[pos.leg_idx]; + const height alt_diff = l.end().alt - l.begin().alt; + return l.begin().alt + alt_diff * ((pos.dist - t.get_leg_dist_offset(pos.leg_idx)) / l.get_length()).common(); +} + +// Returns `x` of the intersection of a glide line and a terrain line. +// y = -x / glide_ratio + pos.alt; +// y = (finish_alt - ground_alt) / dist_to_finish * x + ground_alt + min_agl_height; +distance glide_distance(const flight_point& pos, const glider& g, const task& t, const safety& s, altitude ground_alt) +{ + const auto dist_to_finish = t.get_length() - pos.dist; + return distance((ground_alt + s.min_agl_height - pos.alt).common() / + ((ground_alt - t.get_finish().alt) / dist_to_finish - 1 / glide_ratio(g.polar[0]))); +} + +} + +namespace { + +using namespace glide_computer; + +void print(std::string_view phase_name, timestamp start_ts, const glide_computer::flight_point& point, const glide_computer::flight_point& new_point) +{ + fmt::print( + "| {:<12} | {:>9%.1Q %q} (Total: {:>9%.1Q %q}) | {:>8%.1Q %q} (Total: {:>8%.1Q %q}) | {:>7%.0Q %q} ({:>6%.0Q %q}) |\n", + phase_name, quantity_cast(new_point.ts - point.ts), quantity_cast(new_point.ts - start_ts), + new_point.dist - point.dist, new_point.dist, new_point.alt - point.alt, new_point.alt); +} + +flight_point takeoff(timestamp start_ts, const task& t) +{ + return {start_ts, t.get_start().alt}; +} + +flight_point tow(timestamp start_ts, const flight_point& pos, const aircraft_tow& at) +{ + const duration d = (at.height_agl / at.performance).common(); + const flight_point new_pos{pos.ts + d, pos.alt + at.height_agl, pos.leg_idx, pos.dist}; + + print("Tow", start_ts, pos, new_pos); + return new_pos; +} + +flight_point circle(timestamp start_ts, const flight_point& pos, const glider& g, const weather& w, const task& t, height& height_to_gain) +{ + const height h_agl = agl(pos.alt, terrain_level_alt(t, pos)); + const height circling_height = std::min(w.cloud_base - h_agl, height_to_gain); + const rate_of_climb circling_rate = w.thermal_strength + g.polar[0].climb; + const duration d = (circling_height / circling_rate).common(); + const flight_point new_pos{pos.ts + d, pos.alt + circling_height, pos.leg_idx, pos.dist}; + + height_to_gain -= circling_height; + + print("Circle", start_ts, pos, new_pos); + return new_pos; +} + +flight_point glide(timestamp start_ts, const flight_point& pos, const glider& g, const task& t, const safety& s) +{ + const auto ground_alt = terrain_level_alt(t, pos); + const auto dist = glide_distance(pos, g, t, s, ground_alt); + const auto new_distance = pos.dist + dist; + const auto alt = ground_alt + s.min_agl_height; + const auto l3d = length_3d(dist, pos.alt - alt); + const duration d = l3d / g.polar[0].v.common(); + const flight_point new_pos{pos.ts + d, terrain_level_alt(t, pos) + s.min_agl_height, t.get_leg_index(new_distance), new_distance}; + + print("Glide", start_ts, pos, new_pos); + return new_pos; +} + +flight_point final_glide(timestamp start_ts, const flight_point& pos, const glider& g, const task& t) +{ + const auto dist = t.get_length() - pos.dist; + const auto l3d = length_3d(dist, pos.alt - t.get_finish().alt); + const duration d = l3d / g.polar[0].v.common(); + const flight_point new_pos{pos.ts + d, t.get_finish().alt, t.get_legs().size() - 1, pos.dist + dist}; + + print("Final Glide", start_ts, pos, new_pos); + return new_pos; +} + +} // namespace + +namespace glide_computer { + +void estimate(timestamp start_ts, const glider& g, const weather& w, const task& t, const safety& s, const aircraft_tow& at) +{ + fmt::print("| {:<12} | {:^28} | {:^26} | {:^21} |\n", "Flight phase", "Duration", "Distance", "Height"); + fmt::print("|{0:-^14}|{0:-^30}|{0:-^28}|{0:-^23}|\n", ""); + + // ready to takeoff + flight_point pos = takeoff(start_ts, t); + + // estimate aircraft towing + pos = tow(start_ts, pos, at); + + // estimate the altitude needed to reach the finish line from this place + const altitude final_glide_alt = t.get_finish().alt + height(t.get_length().common() / glide_ratio(g.polar[0])); + + // how much height we still need to gain in the thermalls to reach the destination? + height height_to_gain = final_glide_alt - pos.alt; + + do { + // glide to the next thermall + pos = glide(start_ts, pos, g, t, s); + + // circle in a thermall to gain height + pos = circle(start_ts, pos, g, w, t, height_to_gain); + } while (height_to_gain > height{}); + + // final glide + pos = final_glide(start_ts, pos, g, t); +} + +} // namespace glide_computer diff --git a/example/references/glide_computer.h b/example/references/glide_computer.h new file mode 100644 index 00000000..40341237 --- /dev/null +++ b/example/references/glide_computer.h @@ -0,0 +1,218 @@ +// 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 "geographic.h" +#include +#include +#include +#include +// IWYU pragma: end_exports + +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include + +// An example of a really simplified tactical glide computer +// Simplifications: +// - glider 100% clean and with full factory performance (brand new painting) +// - no influence of the ballast (pilot weight, water, etc) to glider performance +// - only one point on a glider polar curve +// - no influence of bank angle (during circling) on a glider performance +// - no wind +// - constant thermals strength +// - thermals exactly where and when we need them ;-) +// - no airspaces +// - ground level changes linearly between waypoints +// - no ground obstacles (i.e. mountains) to pass +// - flight path exactly on a shortest possible line to destination + +template +struct fmt::formatter : formatter { + template + auto format(const QK& v, FormatContext& ctx) + { + return formatter::format(v.common(), ctx); + } +}; + +namespace glide_computer { + +template +constexpr units::Dimensionless auto operator/(const QK1& lhs, const QK2& rhs) + requires(!units::QuantityKindRelatedTo) && requires { lhs.common() / rhs.common();} +{ + return lhs.common() / rhs.common(); +} + +// kinds +using horizontal_kind = geographic::horizontal_kind; +struct vertical_kind : units::kind {}; +struct vertical_point_kind : units::point_kind {}; +struct velocity_kind : units::derived_kind {}; +struct rate_of_climb_kind : units::derived_kind {}; + +// https://en.wikipedia.org/wiki/Flight_planning#Units_of_measurement +// length +using distance = units::quantity_kind; +using height = units::quantity_kind; +using altitude = units::quantity_point_kind; + +// time +using duration = units::isq::si::time; +using timestamp = units::quantity_point; + +// speed +using velocity = units::quantity_kind; +using rate_of_climb = units::quantity_kind; + +// text output +template +std::basic_ostream& operator<<(std::basic_ostream& os, const altitude& a) +{ + return os << a.relative().common() << " AMSL"; +} + +} // namespace glide_computer + +template<> +struct fmt::formatter : formatter> { + template + auto format(glide_computer::altitude a, FormatContext& ctx) + { + formatter>::format(a.relative().common(), ctx); + return format_to(ctx.out(), " AMSL"); + } +}; + +// definition of glide computer databases and utilities +namespace glide_computer { + +struct glider { + struct polar_point { + velocity v; + rate_of_climb climb; + }; + + std::string name; + std::array polar; +}; + +constexpr units::Dimensionless auto glide_ratio(const glider::polar_point& polar) { return polar.v / -polar.climb; } + +struct weather { + height cloud_base; + rate_of_climb thermal_strength; +}; + +struct waypoint { + std::string name; + geographic::position pos; + altitude alt; +}; + +class task { +public: + using waypoints = std::vector; + + class leg { + const waypoint* begin_; + const waypoint* end_; + distance length_ = geographic::spherical_distance(begin().pos, end().pos); + public: + leg(const waypoint& b, const waypoint& e) noexcept: begin_(&b), end_(&e) {} + constexpr const waypoint& begin() const { return *begin_; }; + constexpr const waypoint& end() const { return *end_; } + constexpr const distance get_length() const { return length_; } + }; + using legs = std::vector; + + template + requires std::same_as, waypoint> + explicit task(const R& r) : waypoints_(std::ranges::begin(r), std::ranges::end(r)) {} + + task(std::initializer_list wpts) : waypoints_(wpts) {} + + const waypoints& get_waypoints() const { return waypoints_; } + const legs& get_legs() const { return legs_; } + + const waypoint& get_start() const { return waypoints_.front(); } + const waypoint& get_finish() const { return waypoints_.back(); } + + distance get_length() const { return length_; } + + distance get_leg_dist_offset(std::size_t leg_index) const { return leg_index == 0 ? distance{} : leg_total_distances_[leg_index - 1]; } + std::size_t get_leg_index(distance dist) const + { + return static_cast(std::ranges::distance(leg_total_distances_.cbegin(), std::ranges::lower_bound(leg_total_distances_, dist))); + } + +private: + waypoints waypoints_; + legs legs_ = make_legs(waypoints_); + std::vector leg_total_distances_ = make_leg_total_distances(legs_); + distance length_ = leg_total_distances_.back(); + + static legs make_legs(const task::waypoints& wpts); + static std::vector make_leg_total_distances(const legs& legs); +}; + +struct safety { + height min_agl_height; +}; + +struct aircraft_tow { + height height_agl; + rate_of_climb performance; +}; + +struct flight_point { + timestamp ts; + altitude alt; + std::size_t leg_idx = 0; + distance dist{}; +}; + +altitude terrain_level_alt(const task& t, const flight_point& pos); + +constexpr height agl(altitude glider_alt, altitude terrain_level) { return glider_alt - terrain_level; } + +inline units::isq::si::length length_3d(distance dist, height h) +{ + // TODO support for hypot(q, q) + return sqrt(pow<2>(dist.common()) + pow<2>(h.common())); +} + +distance glide_distance(const flight_point& pos, const glider& g, const task& t, const safety& s, altitude ground_alt); + +void estimate(timestamp start_ts, const glider& g, const weather& w, const task& t, const safety& s, const aircraft_tow& at); + +} // namespace glide_computer diff --git a/example/glide_computer_example.cpp b/example/references/glide_computer_example.cpp similarity index 100% rename from example/glide_computer_example.cpp rename to example/references/glide_computer_example.cpp diff --git a/example/kalman_filter-alpha_beta_filter_example2.cpp b/example/references/kalman_filter-alpha_beta_filter_example2.cpp similarity index 100% rename from example/kalman_filter-alpha_beta_filter_example2.cpp rename to example/references/kalman_filter-alpha_beta_filter_example2.cpp diff --git a/example/linear_algebra.cpp b/example/references/linear_algebra.cpp similarity index 100% rename from example/linear_algebra.cpp rename to example/references/linear_algebra.cpp diff --git a/example/references/measurement.cpp b/example/references/measurement.cpp new file mode 100644 index 00000000..62dc7dac --- /dev/null +++ b/example/references/measurement.cpp @@ -0,0 +1,157 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +// root sum of squares +template +T rss(const T& v1, const T& v2) +{ + return std::sqrt(std::pow(v1, 2) + std::pow(v2, 2)); +} + +template +class measurement { +public: + using value_type = T; + + measurement() = default; + + constexpr explicit measurement(const value_type& val, const value_type& err = {}) : + value_(val), + uncertainty_(std::abs(err)) + { + } + + constexpr const value_type& value() const { return value_; } + constexpr const value_type& uncertainty() const { return uncertainty_; } + + constexpr value_type relative_uncertainty() const { return uncertainty() / value(); } + constexpr value_type lower_bound() const { return value() - uncertainty(); } + constexpr value_type upper_bound() const { return value() + uncertainty(); } + + [[nodiscard]] constexpr measurement operator-() const { return measurement(-value(), uncertainty()); } + + [[nodiscard]] friend constexpr measurement operator+(const measurement& lhs, const measurement& rhs) + { + return measurement(lhs.value() + rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator-(const measurement& lhs, const measurement& rhs) + { + return measurement(lhs.value() - rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const measurement& rhs) + { + const auto val = lhs.value() * rhs.value(); + return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const value_type& value) + { + const auto val = lhs.value() * value; + return measurement(val, val * lhs.relative_uncertainty()); + } + + [[nodiscard]] friend constexpr measurement operator*(const value_type& value, const measurement& rhs) + { + const auto val = rhs.value() * value; + return measurement(val, val * rhs.relative_uncertainty()); + } + + [[nodiscard]] friend constexpr measurement operator/(const measurement& lhs, const measurement& rhs) + { + const auto val = lhs.value() / rhs.value(); + return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator/(const measurement& lhs, const value_type& value) + { + const auto val = lhs.value() / value; + return measurement(val, val * lhs.relative_uncertainty()); + } + + [[nodiscard]] friend constexpr measurement operator/(const value_type& value, const measurement& rhs) + { + const auto val = value / rhs.value(); + return measurement(val, val * rhs.relative_uncertainty()); + } + + [[nodiscard]] constexpr auto operator<=>(const measurement&) const = default; + + friend std::ostream& operator<<(std::ostream& os, const measurement& v) + { + return os << v.value() << " ± " << v.uncertainty(); + } + +private: + value_type value_{}; + value_type uncertainty_{}; +}; + +} // namespace + + +namespace { + +static_assert(units::Representation>); + +void example() +{ + using namespace units::isq; + + const auto a = si::acceleration>(measurement(9.8, 0.1)); + const auto t = si::time>(measurement(1.2, 0.1)); + + const Speed auto v1 = a * t; +#if UNITS_DOWNCAST_MODE == 0 + std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast(v1) << '\n'; +#else + std::cout << a << " * " << t << " = " << v1 << " = " << quantity_cast(v1) << '\n'; +#endif + + si::length> length(measurement(123., 1.)); + std::cout << "10 * " << length << " = " << 10 * length << '\n'; +} + +} // namespace + +int main() +{ + try { + example(); + } catch (const std::exception& ex) { + std::cerr << "Unhandled std exception caught: " << ex.what() << '\n'; + } catch (...) { + std::cerr << "Unhandled unknown exception caught\n"; + } +} diff --git a/example/total_energy.cpp b/example/references/total_energy.cpp similarity index 100% rename from example/total_energy.cpp rename to example/references/total_energy.cpp diff --git a/example/unknown_dimension.cpp b/example/references/unknown_dimension.cpp similarity index 100% rename from example/unknown_dimension.cpp rename to example/references/unknown_dimension.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3cbd9c9c..6af8b3b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,9 +27,11 @@ project(mp-units ) option(UNITS_AS_SYSTEM_HEADERS "Exports library as system headers" OFF) +option(UNITS_REFERENCES "Enables definitions of Quantity References provided for quantities of various units" ON) option(UNITS_LITERALS "Enables definitions of User Defined Literals (UDLs) provided for quantities of various units" OFF) message(STATUS "UNITS_AS_SYSTEM_HEADERS: ${UNITS_AS_SYSTEM_HEADERS}") +message(STATUS "UNITS_REFERENCES: ${UNITS_REFERENCES}") message(STATUS "UNITS_LITERALS: ${UNITS_LITERALS}") list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") diff --git a/src/cmake/AddUnitsModule.cmake b/src/cmake/AddUnitsModule.cmake index 694e0620..856c4921 100644 --- a/src/cmake/AddUnitsModule.cmake +++ b/src/cmake/AddUnitsModule.cmake @@ -45,5 +45,8 @@ endfunction() # function(add_units_system name) add_units_module(${name} ${ARGN}) - target_compile_definitions(mp-units-${name} INTERFACE $<$:UNITS_LITERALS>) + target_compile_definitions(mp-units-${name} INTERFACE + $<$:UNITS_REFERENCES> + $<$:UNITS_LITERALS> + ) endfunction() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c30b9179..0b5539ac 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -55,7 +55,10 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") ) endif() -target_compile_definitions(mp-units-core INTERFACE $<$:UNITS_LITERALS>) +target_compile_definitions(mp-units-core INTERFACE + $<$:UNITS_REFERENCES> + $<$:UNITS_LITERALS> +) if(DEFINED UNITS_DOWNCAST_MODE) set(downcast_mode_options OFF ON AUTO) diff --git a/src/core/include/units/generic/angle.h b/src/core/include/units/generic/angle.h index fb4e1ad5..26fdd80c 100644 --- a/src/core/include/units/generic/angle.h +++ b/src/core/include/units/generic/angle.h @@ -55,10 +55,14 @@ constexpr auto operator"" _q_rad(long double l) { return angle, radian>{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/modulation_rate.h b/src/systems/isq-iec80000/include/units/isq/iec80000/modulation_rate.h index 9dabdd5c..81cd60f1 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/modulation_rate.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/modulation_rate.h @@ -68,6 +68,8 @@ constexpr auto operator"" _q_YBd(unsigned long long l) { gsl_ExpectsAudit(std::i #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { inline constexpr auto Bd = reference{}; @@ -82,4 +84,6 @@ inline constexpr auto YBd = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::iec80000 diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h index 28b71036..88ca062d 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/storage_capacity.h @@ -125,6 +125,8 @@ constexpr auto operator"" _q_PiB(unsigned long long l) { gsl_ExpectsAudit(std::i #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { // bits @@ -167,4 +169,6 @@ inline constexpr auto PiB = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::iec80000 diff --git a/src/systems/isq-iec80000/include/units/isq/iec80000/traffic_intensity.h b/src/systems/isq-iec80000/include/units/isq/iec80000/traffic_intensity.h index f575e797..e74b2c7d 100644 --- a/src/systems/isq-iec80000/include/units/isq/iec80000/traffic_intensity.h +++ b/src/systems/isq-iec80000/include/units/isq/iec80000/traffic_intensity.h @@ -53,10 +53,14 @@ constexpr auto operator"" _q_E(unsigned long long l) { gsl_ExpectsAudit(std::in_ #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { inline constexpr auto E = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::iec80000 diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/acceleration.h b/src/systems/si-cgs/include/units/isq/si/cgs/acceleration.h index cfc19f07..4430d92f 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/acceleration.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/acceleration.h @@ -52,10 +52,14 @@ constexpr auto operator"" _q_Gal(long double l) { return acceleration{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/area.h b/src/systems/si-cgs/include/units/isq/si/cgs/area.h index 36628d6c..b72808b7 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/area.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/area.h @@ -54,10 +54,14 @@ constexpr auto operator"" _q_cm2(long double l) { return area{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/energy.h b/src/systems/si-cgs/include/units/isq/si/cgs/energy.h index fb93205c..808d0802 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/energy.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/energy.h @@ -54,10 +54,14 @@ constexpr auto operator"" _q_erg(long double l) { return energy{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/force.h b/src/systems/si-cgs/include/units/isq/si/cgs/force.h index 4b64a807..08619053 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/force.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/force.h @@ -55,10 +55,14 @@ constexpr auto operator"" _q_dyn(long double l) { return force{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/length.h b/src/systems/si-cgs/include/units/isq/si/cgs/length.h index b1a8de90..722bba47 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/length.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/length.h @@ -53,10 +53,14 @@ constexpr auto operator"" _q_cm(long double l) { return length{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/mass.h b/src/systems/si-cgs/include/units/isq/si/cgs/mass.h index e2627787..79b5cc9e 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/mass.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/mass.h @@ -53,10 +53,14 @@ constexpr auto operator"" _q_g(long double l) { return mass(l #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { inline constexpr auto g = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/pressure.h b/src/systems/si-cgs/include/units/isq/si/cgs/pressure.h index 1686077c..2edf358c 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/pressure.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/pressure.h @@ -55,10 +55,14 @@ constexpr auto operator"" _q_Ba(long double l) { return pressure{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-cgs/include/units/isq/si/cgs/time.h b/src/systems/si-cgs/include/units/isq/si/cgs/time.h index 58949423..ff7cfb45 100644 --- a/src/systems/si-cgs/include/units/isq/si/cgs/time.h +++ b/src/systems/si-cgs/include/units/isq/si/cgs/time.h @@ -47,10 +47,14 @@ using si::literals::operator"" _q_s; #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { using si::references::s; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::cgs diff --git a/src/systems/si-fps/include/units/isq/si/fps/area.h b/src/systems/si-fps/include/units/isq/si/fps/area.h index 62db900d..836b1e02 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/area.h +++ b/src/systems/si-fps/include/units/isq/si/fps/area.h @@ -53,10 +53,14 @@ constexpr auto operator"" _q_ft2(long double l) { return area{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/force.h b/src/systems/si-fps/include/units/isq/si/fps/force.h index 58cd3d86..ccb61440 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/force.h +++ b/src/systems/si-fps/include/units/isq/si/fps/force.h @@ -72,6 +72,8 @@ constexpr auto operator"" _q_klbf(long double l) { return force{}; @@ -80,4 +82,6 @@ inline constexpr auto klbf = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/length.h b/src/systems/si-fps/include/units/isq/si/fps/length.h index 2fb961ea..1e40e0d4 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/length.h +++ b/src/systems/si-fps/include/units/isq/si/fps/length.h @@ -102,6 +102,8 @@ constexpr auto operator"" _q_naut_mi(long double l) { return length{}; @@ -117,4 +119,6 @@ inline constexpr auto naut_mi = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/mass.h b/src/systems/si-fps/include/units/isq/si/fps/mass.h index ae919f13..b6bfdf86 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/mass.h +++ b/src/systems/si-fps/include/units/isq/si/fps/mass.h @@ -102,6 +102,8 @@ constexpr auto operator"" _q_lton(long double l) { return mass{}; @@ -116,4 +118,6 @@ inline constexpr auto lton = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/power.h b/src/systems/si-fps/include/units/isq/si/fps/power.h index 29892778..c797f041 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/power.h +++ b/src/systems/si-fps/include/units/isq/si/fps/power.h @@ -66,10 +66,14 @@ constexpr auto operator"" _q_hp(long double l) { return power{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/pressure.h b/src/systems/si-fps/include/units/isq/si/fps/pressure.h index b607724d..33d3dda6 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/pressure.h +++ b/src/systems/si-fps/include/units/isq/si/fps/pressure.h @@ -69,6 +69,8 @@ constexpr auto operator"" _q_kpsi(long double l) { return pressure{}; @@ -76,4 +78,6 @@ inline constexpr auto kpsi = reference{}; @@ -75,4 +77,6 @@ inline constexpr auto knot = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/time.h b/src/systems/si-fps/include/units/isq/si/fps/time.h index 9ff6dd9b..bd7f7de0 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/time.h +++ b/src/systems/si-fps/include/units/isq/si/fps/time.h @@ -51,10 +51,14 @@ using si::literals::operator"" _q_s; #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { using si::references::s; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-fps/include/units/isq/si/fps/volume.h b/src/systems/si-fps/include/units/isq/si/fps/volume.h index 509fa1cb..a4b66fa7 100644 --- a/src/systems/si-fps/include/units/isq/si/fps/volume.h +++ b/src/systems/si-fps/include/units/isq/si/fps/volume.h @@ -58,6 +58,8 @@ constexpr auto operator"" _q_yd3(long double l) { return volume{}; @@ -65,4 +67,6 @@ inline constexpr auto yd3 = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::fps diff --git a/src/systems/si-iau/include/units/isq/si/iau/length.h b/src/systems/si-iau/include/units/isq/si/iau/length.h index 6f8eaf39..521413e3 100644 --- a/src/systems/si-iau/include/units/isq/si/iau/length.h +++ b/src/systems/si-iau/include/units/isq/si/iau/length.h @@ -64,6 +64,8 @@ constexpr auto operator"" _q_angstrom(long double l) { return si::length{}; @@ -72,4 +74,6 @@ inline constexpr auto angstrom = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::iau diff --git a/src/systems/si-imperial/include/units/isq/si/imperial/length.h b/src/systems/si-imperial/include/units/isq/si/imperial/length.h index b82cab67..fb1a0366 100644 --- a/src/systems/si-imperial/include/units/isq/si/imperial/length.h +++ b/src/systems/si-imperial/include/units/isq/si/imperial/length.h @@ -56,6 +56,8 @@ constexpr auto operator"" _q_rd(long double l) { return si::length{}; @@ -63,4 +65,6 @@ inline constexpr auto rd = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::imperial diff --git a/src/systems/si-international/include/units/isq/si/international/area.h b/src/systems/si-international/include/units/isq/si/international/area.h index 83ddd1ab..5e657ad4 100644 --- a/src/systems/si-international/include/units/isq/si/international/area.h +++ b/src/systems/si-international/include/units/isq/si/international/area.h @@ -49,10 +49,14 @@ constexpr auto operator"" _q_ft2(long double l) { return si::area{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::international diff --git a/src/systems/si-international/include/units/isq/si/international/length.h b/src/systems/si-international/include/units/isq/si/international/length.h index 3ccad915..01b7bc16 100644 --- a/src/systems/si-international/include/units/isq/si/international/length.h +++ b/src/systems/si-international/include/units/isq/si/international/length.h @@ -106,6 +106,8 @@ constexpr auto operator"" _q_mil(long double l) { return si::length{}; @@ -119,4 +121,6 @@ inline constexpr auto mil = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::international diff --git a/src/systems/si-international/include/units/isq/si/international/volume.h b/src/systems/si-international/include/units/isq/si/international/volume.h index 22d0881b..69e34a2c 100644 --- a/src/systems/si-international/include/units/isq/si/international/volume.h +++ b/src/systems/si-international/include/units/isq/si/international/volume.h @@ -49,10 +49,14 @@ constexpr auto operator"" _q_ft3(long double l) { return si::volume{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::international diff --git a/src/systems/si-typographic/include/units/isq/si/typographic/length.h b/src/systems/si-typographic/include/units/isq/si/typographic/length.h index da2795cb..4dc404b1 100644 --- a/src/systems/si-typographic/include/units/isq/si/typographic/length.h +++ b/src/systems/si-typographic/include/units/isq/si/typographic/length.h @@ -65,6 +65,8 @@ constexpr auto operator"" _q_point_prn(long double l) { return si::length{}; @@ -74,4 +76,6 @@ inline constexpr auto point_prn = reference{}; @@ -73,4 +75,6 @@ inline constexpr auto mi = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si::us diff --git a/src/systems/si/include/units/isq/si/absorbed_dose.h b/src/systems/si/include/units/isq/si/absorbed_dose.h index 8215a412..31d07dea 100644 --- a/src/systems/si/include/units/isq/si/absorbed_dose.h +++ b/src/systems/si/include/units/isq/si/absorbed_dose.h @@ -154,6 +154,8 @@ constexpr auto operator"" _q_YGy(long double l) { return absorbed_dose{}; @@ -180,4 +182,6 @@ inline constexpr auto YGy = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/amount_of_substance.h b/src/systems/si/include/units/isq/si/amount_of_substance.h index 65950e53..bf066393 100644 --- a/src/systems/si/include/units/isq/si/amount_of_substance.h +++ b/src/systems/si/include/units/isq/si/amount_of_substance.h @@ -53,10 +53,14 @@ constexpr auto operator"" _q_mol(long double l) { return amount_of_substance{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/area.h b/src/systems/si/include/units/isq/si/area.h index 9ac0121b..15732212 100644 --- a/src/systems/si/include/units/isq/si/area.h +++ b/src/systems/si/include/units/isq/si/area.h @@ -159,6 +159,8 @@ constexpr auto operator"" _q_ha(long double l) { return area{}; @@ -186,4 +188,6 @@ inline constexpr auto ha = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/capacitance.h b/src/systems/si/include/units/isq/si/capacitance.h index 017440ca..2799c20b 100644 --- a/src/systems/si/include/units/isq/si/capacitance.h +++ b/src/systems/si/include/units/isq/si/capacitance.h @@ -155,6 +155,8 @@ constexpr auto operator"" _q_YF(long double l) { return capacitance{}; @@ -181,4 +183,6 @@ inline constexpr auto YF = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/catalytic_activity.h b/src/systems/si/include/units/isq/si/catalytic_activity.h index b3f8034f..6eb94169 100644 --- a/src/systems/si/include/units/isq/si/catalytic_activity.h +++ b/src/systems/si/include/units/isq/si/catalytic_activity.h @@ -161,6 +161,8 @@ constexpr auto operator"" _q_U(long double l) { return catalytic_activity{}; @@ -188,5 +190,7 @@ inline constexpr auto U = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/conductance.h b/src/systems/si/include/units/isq/si/conductance.h index 5bed5f9b..b03838c3 100644 --- a/src/systems/si/include/units/isq/si/conductance.h +++ b/src/systems/si/include/units/isq/si/conductance.h @@ -134,6 +134,8 @@ constexpr auto operator"" _q_YS(long double l) { return conductance{}; @@ -156,5 +158,7 @@ inline constexpr auto YS = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/electric_charge.h b/src/systems/si/include/units/isq/si/electric_charge.h index 325c30a0..7457e2e7 100644 --- a/src/systems/si/include/units/isq/si/electric_charge.h +++ b/src/systems/si/include/units/isq/si/electric_charge.h @@ -54,10 +54,14 @@ constexpr auto operator"" _q_C(long double l) { return electric_charge{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/electric_current.h b/src/systems/si/include/units/isq/si/electric_current.h index 4eb9e2db..236b45b5 100644 --- a/src/systems/si/include/units/isq/si/electric_current.h +++ b/src/systems/si/include/units/isq/si/electric_current.h @@ -153,6 +153,8 @@ constexpr auto operator"" _q_YA(long double l) { return electric_current{}; @@ -179,4 +181,6 @@ inline constexpr auto YA = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/energy.h b/src/systems/si/include/units/isq/si/energy.h index 7a1e09c1..bf2a7aaf 100644 --- a/src/systems/si/include/units/isq/si/energy.h +++ b/src/systems/si/include/units/isq/si/energy.h @@ -145,6 +145,8 @@ constexpr auto operator"" _q_GeV(long double l) { return energy{}; @@ -169,4 +171,6 @@ inline constexpr auto GeV = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/force.h b/src/systems/si/include/units/isq/si/force.h index 8118b66c..4dd17ae2 100644 --- a/src/systems/si/include/units/isq/si/force.h +++ b/src/systems/si/include/units/isq/si/force.h @@ -155,6 +155,8 @@ constexpr auto operator"" _q_YN(long double l) { return force{}; @@ -181,4 +183,6 @@ inline constexpr auto YN = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/frequency.h b/src/systems/si/include/units/isq/si/frequency.h index c58cab83..61e4ab9f 100644 --- a/src/systems/si/include/units/isq/si/frequency.h +++ b/src/systems/si/include/units/isq/si/frequency.h @@ -133,6 +133,8 @@ constexpr auto operator"" _q_YHz(long double l) { return frequency{}; @@ -155,4 +157,6 @@ inline constexpr auto YHz = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/inductance.h b/src/systems/si/include/units/isq/si/inductance.h index b55e68a1..a5853aae 100644 --- a/src/systems/si/include/units/isq/si/inductance.h +++ b/src/systems/si/include/units/isq/si/inductance.h @@ -135,6 +135,8 @@ constexpr auto operator"" _q_YH(long double l) { return inductance{}; @@ -157,4 +159,6 @@ inline constexpr auto YH = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/length.h b/src/systems/si/include/units/isq/si/length.h index 73523378..a608b5ee 100644 --- a/src/systems/si/include/units/isq/si/length.h +++ b/src/systems/si/include/units/isq/si/length.h @@ -159,6 +159,8 @@ constexpr auto operator"" _q_au(long double l) { return length{}; @@ -186,4 +188,6 @@ inline constexpr auto au = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/luminous_intensity.h b/src/systems/si/include/units/isq/si/luminous_intensity.h index 7f6f2cf7..cef5eca6 100644 --- a/src/systems/si/include/units/isq/si/luminous_intensity.h +++ b/src/systems/si/include/units/isq/si/luminous_intensity.h @@ -153,6 +153,8 @@ constexpr auto operator"" _q_Ycd(long double l) { return luminous_intensity{}; @@ -179,4 +181,6 @@ inline constexpr auto Ycd = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/magnetic_flux.h b/src/systems/si/include/units/isq/si/magnetic_flux.h index 10eaabee..9c7d6939 100644 --- a/src/systems/si/include/units/isq/si/magnetic_flux.h +++ b/src/systems/si/include/units/isq/si/magnetic_flux.h @@ -135,6 +135,8 @@ constexpr auto operator"" _q_YWb(long double l) { return magnetic_flux{}; @@ -157,4 +159,6 @@ inline constexpr auto YWb = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/magnetic_induction.h b/src/systems/si/include/units/isq/si/magnetic_induction.h index 33768eee..2d275f73 100644 --- a/src/systems/si/include/units/isq/si/magnetic_induction.h +++ b/src/systems/si/include/units/isq/si/magnetic_induction.h @@ -143,6 +143,8 @@ constexpr auto operator"" _q_G(long double l) { return magnetic_induction{}; @@ -166,4 +168,6 @@ inline constexpr auto G = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units diff --git a/src/systems/si/include/units/isq/si/mass.h b/src/systems/si/include/units/isq/si/mass.h index 7f2d9318..7a2c248b 100644 --- a/src/systems/si/include/units/isq/si/mass.h +++ b/src/systems/si/include/units/isq/si/mass.h @@ -189,9 +189,10 @@ constexpr auto operator"" _q_zt(long double l) { return mass(l)); return mass(static_cast(l)); } constexpr auto operator"" _q_at(long double l) { return mass(l); } +// TODO Collides with foot // ft -constexpr auto operator"" _q_ft(unsigned long long l) { gsl_ExpectsAudit(std::in_range(l)); return mass(static_cast(l)); } -constexpr auto operator"" _q_ft(long double l) { return mass(l); } +// constexpr auto operator"" _q_ft(unsigned long long l) { gsl_ExpectsAudit(std::in_range(l)); return mass(static_cast(l)); } +// constexpr auto operator"" _q_ft(long double l) { return mass(l); } // pt constexpr auto operator"" _q_pt(unsigned long long l) { gsl_ExpectsAudit(std::in_range(l)); return mass(static_cast(l)); } @@ -265,6 +266,8 @@ constexpr auto operator"" _q_Da(long double l) { return mass{}; @@ -313,4 +316,6 @@ inline constexpr auto Da = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/power.h b/src/systems/si/include/units/isq/si/power.h index 191d8a41..0b352b40 100644 --- a/src/systems/si/include/units/isq/si/power.h +++ b/src/systems/si/include/units/isq/si/power.h @@ -134,6 +134,8 @@ constexpr auto operator"" _q_YW(long double l) { return power{}; @@ -156,4 +158,6 @@ inline constexpr auto YW = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/pressure.h b/src/systems/si/include/units/isq/si/pressure.h index e79347e0..9f03d8ac 100644 --- a/src/systems/si/include/units/isq/si/pressure.h +++ b/src/systems/si/include/units/isq/si/pressure.h @@ -155,6 +155,8 @@ constexpr auto operator"" _q_YPa(long double l) { return pressure{}; @@ -181,4 +183,6 @@ inline constexpr auto YPa = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/radioactivity.h b/src/systems/si/include/units/isq/si/radioactivity.h index ca6731b8..7738f323 100644 --- a/src/systems/si/include/units/isq/si/radioactivity.h +++ b/src/systems/si/include/units/isq/si/radioactivity.h @@ -153,6 +153,8 @@ constexpr auto operator"" _q_YBq(long double l) { return radioactivity{}; @@ -179,4 +181,6 @@ inline constexpr auto YBq = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/resistance.h b/src/systems/si/include/units/isq/si/resistance.h index 584c18a8..7d46f76e 100644 --- a/src/systems/si/include/units/isq/si/resistance.h +++ b/src/systems/si/include/units/isq/si/resistance.h @@ -135,6 +135,8 @@ constexpr auto operator"" _q_YR(long double l) { return resistance{}; @@ -157,4 +159,6 @@ inline constexpr auto YR = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/thermodynamic_temperature.h b/src/systems/si/include/units/isq/si/thermodynamic_temperature.h index 9ec6a4dd..902dbc62 100644 --- a/src/systems/si/include/units/isq/si/thermodynamic_temperature.h +++ b/src/systems/si/include/units/isq/si/thermodynamic_temperature.h @@ -52,10 +52,14 @@ constexpr auto operator"" _q_K(long double l) { return thermodynamic_temperature #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { inline constexpr auto K = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/time.h b/src/systems/si/include/units/isq/si/time.h index 74395c1f..bfc2e13c 100644 --- a/src/systems/si/include/units/isq/si/time.h +++ b/src/systems/si/include/units/isq/si/time.h @@ -108,6 +108,8 @@ constexpr auto operator"" _q_d(long double l) { return time(l) #endif // UNITS_LITERALS +#ifdef UNITS_REFERENCES + namespace references { inline constexpr auto ys = reference{}; @@ -125,4 +127,6 @@ inline constexpr auto d = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/voltage.h b/src/systems/si/include/units/isq/si/voltage.h index bab909eb..8d323900 100644 --- a/src/systems/si/include/units/isq/si/voltage.h +++ b/src/systems/si/include/units/isq/si/voltage.h @@ -155,6 +155,8 @@ constexpr auto operator"" _q_YV(long double l) { return voltage{}; @@ -181,4 +183,6 @@ inline constexpr auto YV = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/src/systems/si/include/units/isq/si/volume.h b/src/systems/si/include/units/isq/si/volume.h index f3c03e7d..505f7f31 100644 --- a/src/systems/si/include/units/isq/si/volume.h +++ b/src/systems/si/include/units/isq/si/volume.h @@ -259,6 +259,8 @@ constexpr auto operator"" _q_Yl(long double l) { return volume{}; @@ -306,4 +308,6 @@ inline constexpr auto Yl = reference{}; } // namespace references +#endif // UNITS_REFERENCES + } // namespace units::isq::si diff --git a/test/unit_test/runtime/CMakeLists.txt b/test/unit_test/runtime/CMakeLists.txt index 95550826..b8537ccd 100644 --- a/test/unit_test/runtime/CMakeLists.txt +++ b/test/unit_test/runtime/CMakeLists.txt @@ -35,7 +35,10 @@ target_link_libraries(unit_tests_runtime PRIVATE mp-units::mp-units Catch2::Catch2 ) -target_compile_definitions(unit_tests_runtime PRIVATE UNITS_LITERALS) +target_compile_definitions(unit_tests_runtime PRIVATE + UNITS_REFERENCES + UNITS_LITERALS +) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(unit_tests_runtime PRIVATE diff --git a/test/unit_test/static/CMakeLists.txt b/test/unit_test/static/CMakeLists.txt index 765ab5c2..399e6fa6 100644 --- a/test/unit_test/static/CMakeLists.txt +++ b/test/unit_test/static/CMakeLists.txt @@ -37,7 +37,10 @@ target_link_libraries(unit_tests_static_truncating PRIVATE target_compile_options(unit_tests_static_truncating PRIVATE $,/wd4242 /wd4244,-Wno-conversion> ) -target_compile_definitions(unit_tests_static_truncating PRIVATE UNITS_LITERALS) +target_compile_definitions(unit_tests_static_truncating PRIVATE + UNITS_REFERENCES + UNITS_LITERALS +) add_library(unit_tests_static cgs_test.cpp @@ -74,4 +77,7 @@ target_link_libraries(unit_tests_static PRIVATE unit_tests_static_truncating mp-units::mp-units ) -target_compile_definitions(unit_tests_static PRIVATE UNITS_LITERALS) +target_compile_definitions(unit_tests_static PRIVATE + UNITS_REFERENCES + UNITS_LITERALS +) diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index 8a5eec85..f04c2b0b 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -29,3 +29,4 @@ find_package(mp-units CONFIG REQUIRED) add_executable(test_package test_package.cpp) target_link_libraries(test_package PRIVATE mp-units::mp-units) +target_compile_definitions(test_package PRIVATE UNITS_REFERENCES)