diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 58d96571..8b704120 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -58,7 +58,7 @@ add_example( strong_angular_quantities mp-units::core-fmt mp-units::core-io mp-units::si mp-units::isq_angle mp-units::utility ) add_example(total_energy mp-units::core-io mp-units::si mp-units::natural mp-units::utility) -add_example(unmanned_aerial_vehicle mp-units::core-io mp-units::si mp-units::international) +add_example(unmanned_aerial_vehicle mp-units::core-fmt mp-units::core-io mp-units::si mp-units::international mp-units::utility example_utils) find_package(wg21_linear_algebra CONFIG REQUIRED) add_example(linear_algebra mp-units::core-fmt mp-units::core-io mp-units::si) diff --git a/example/unmanned_aerial_vehicle.cpp b/example/unmanned_aerial_vehicle.cpp index c1e42652..634a0109 100644 --- a/example/unmanned_aerial_vehicle.cpp +++ b/example/unmanned_aerial_vehicle.cpp @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include "geographic.h" #include #include #include @@ -28,16 +29,113 @@ #include using namespace mp_units; +using namespace geographic; + +// **** HAE **** + +enum class earth_gravity_model { egm84_15, egm95_5, egm2008_1 }; + +template +struct height_above_ellipsoid_t : absolute_point_origin { + static constexpr earth_gravity_model egm = M; +}; +template +inline constexpr height_above_ellipsoid_t height_above_ellipsoid; + +template +using hae_altitude = quantity_point>; + +constexpr const char* to_text(earth_gravity_model m) +{ + switch (m) { + using enum earth_gravity_model; + case egm84_15: + return "EGM84-15"; + case egm95_5: + return "EGM95-5"; + case egm2008_1: + return "EGM2008-1"; + } +} + +// TODO Why gcc does not deduce `M`? Is it a gcc bug? +// template +// std::basic_ostream& operator<<(std::basic_ostream& os, const hae_altitude& a) +// { +// return os << a.absolute() << " HAE(" << to_text(M) << ")"; +// } + +// template +// struct STD_FMT::formatter> : formatter::quantity_type> { +// template +// auto format(const hae_altitude& a, FormatContext& ctx) +// { +// formatter::quantity_type>::format(a.absolute(), ctx); +// return STD_FMT::format_to(ctx.out(), " HAE({})", to_text(M)); +// } +// }; + +template +std::basic_ostream& operator<<(std::basic_ostream& os, + const hae_altitude& a) +{ + return os << a.absolute() << " HAE(" << to_text(earth_gravity_model::egm2008_1) << ")"; +} + +template<> +struct STD_FMT::formatter> : + formatter::quantity_type> { + template + auto format(const hae_altitude& a, FormatContext& ctx) + { + formatter::quantity_type>::format(a.absolute(), ctx); + return STD_FMT::format_to(ctx.out(), " HAE({})", to_text(earth_gravity_model::egm2008_1)); + } +}; + +double GeographicLibWhatsMyOffset(long double /* lat */, long double /* lon */) +{ + // for example use GeographicLib for that: + // - https://geographiclib.sourceforge.io/C++/doc/geoid.html + // - https://conan.io/center/geographiclib + return 29.49; +} + +template +hae_altitude to_hae(msl_altitude msl, position pos) +{ + const auto geoid_undulation = + isq::height(GeographicLibWhatsMyOffset(pos.lat.number_in(si::degree), pos.lon.number_in(si::degree)) * si::metre); + return msl.absolute() - geoid_undulation; +} + + +// **** HAL **** // clang-format off -inline constexpr struct mean_sea_level : absolute_point_origin {} mean_sea_level; inline constexpr struct height_above_launch : absolute_point_origin {} height_above_launch; // clang-format on -using msl_altitude = quantity_point; using hal_altitude = quantity_point; -static_assert(!std::equality_comparable_with); +template +std::basic_ostream& operator<<(std::basic_ostream& os, const hal_altitude& a) +{ + return os << a.absolute() << " HAL"; +} + +template<> +struct STD_FMT::formatter : formatter { + template + auto format(const hal_altitude& a, FormatContext& ctx) + { + formatter::format(a.absolute(), ctx); + return STD_FMT::format_to(ctx.out(), " HAL"); + } +}; + + +// **** UAV **** class unmanned_aerial_vehicle { msl_altitude current_ = 0 * si::metre; @@ -61,8 +159,18 @@ int main() unmanned_aerial_vehicle uav; uav.take_off(6'000 * ft); uav.current(10'000 * ft); - std::cout << "hal = " << uav.hal().relative() << "\n"; + std::cout << STD_FMT::format("hal = {}\n", uav.hal()); msl_altitude ground_level = 123 * m; - std::cout << "agl = " << uav.current() - ground_level << "\n"; + std::cout << STD_FMT::format("agl = {}\n", uav.current() - ground_level); + + struct waypoint { + std::string name; + geographic::position pos; + msl_altitude msl_alt; + }; + + waypoint wpt = {"EPPR", {54.24772_N, 18.6745_E}, msl_altitude{16. * ft}}; + std::cout << STD_FMT::format("{}: {} {}, {:%.2Q %q}, {:%.2Q %q}\n", wpt.name, wpt.pos.lat, wpt.pos.lon, wpt.msl_alt, + to_hae(wpt.msl_alt, wpt.pos)); }