Units.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty. In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  * claim that you wrote the original software. If you use this software
14  * in a product, an acknowledgment in the product documentation would be
15  * appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  * misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  */
20 
38 #ifndef PLAYRHO_COMMON_UNITS_HPP
39 #define PLAYRHO_COMMON_UNITS_HPP
40 
43 #include <type_traits>
44 #include <cmath>
45 
46 // #define USE_BOOST_UNITS
47 #if defined(USE_BOOST_UNITS)
48 #include <boost/units/io.hpp>
49 #include <boost/units/limits.hpp>
50 #include <boost/units/cmath.hpp>
51 #include <boost/units/systems/si/length.hpp>
52 #include <boost/units/systems/si/time.hpp>
53 #include <boost/units/systems/si/velocity.hpp>
54 #include <boost/units/systems/si/acceleration.hpp>
55 #include <boost/units/systems/si/frequency.hpp>
56 #include <boost/units/systems/si/velocity.hpp>
57 #include <boost/units/systems/si/mass.hpp>
58 #include <boost/units/systems/si/momentum.hpp>
59 #include <boost/units/systems/si/inverse_mass.hpp>
60 #include <boost/units/systems/si/area.hpp>
61 #include <boost/units/systems/si/plane_angle.hpp>
62 #include <boost/units/systems/si/angular_momentum.hpp>
63 #include <boost/units/systems/si/angular_velocity.hpp>
64 #include <boost/units/systems/si/angular_acceleration.hpp>
65 #include <boost/units/systems/si/second_moment_of_area.hpp>
66 #include <boost/units/systems/si/surface_density.hpp>
67 #include <boost/units/systems/si/moment_of_inertia.hpp>
68 #include <boost/units/systems/si/inverse_moment_of_inertia.hpp>
69 #include <boost/units/systems/si/force.hpp>
70 #include <boost/units/systems/si/torque.hpp>
71 #include <boost/units/systems/angle/degrees.hpp>
72 #endif // defined(USE_BOOST_UNITS)
73 
74 // Define quantity and unit related macros to abstract away C-preprocessor definitions
75 #if defined(USE_BOOST_UNITS)
76 #define PLAYRHO_QUANTITY(BoostDimension) boost::units::quantity<BoostDimension, Real>
77 #define PLAYRHO_UNIT(Quantity, BoostUnit) Quantity{BoostUnit * Real{1}}
78 #define PLAYRHO_DERIVED_UNIT(Quantity, BoostUnit, Ratio) Quantity{BoostUnit * Real{Ratio}}
79 #else // defined(USE_BOOST_UNITS)
80 #define PLAYRHO_QUANTITY(BoostDimension) Real
81 #define PLAYRHO_UNIT(Quantity, BoostUnit) Real{1}
82 #define PLAYRHO_DERIVED_UNIT(Quantity, BoostUnit, Ratio) Real{Ratio}}
83 #endif // defined(USE_BOOST_UNITS)
84 
85 namespace playrho
86 {
96 
103  using Time = PLAYRHO_QUANTITY(boost::units::si::time);
104 
113  using Frequency = PLAYRHO_QUANTITY(boost::units::si::frequency);
114 
121  using Length = PLAYRHO_QUANTITY(boost::units::si::length);
122 
130  using LinearVelocity = PLAYRHO_QUANTITY(boost::units::si::velocity);
131 
139  using LinearAcceleration = PLAYRHO_QUANTITY(boost::units::si::acceleration);
140 
147  using Mass = PLAYRHO_QUANTITY(boost::units::si::mass);
148 
154  using InvMass = PLAYRHO_QUANTITY(boost::units::si::inverse_mass);
155 
163  using Area = PLAYRHO_QUANTITY(boost::units::si::area);
164 
172  using AreaDensity = PLAYRHO_QUANTITY(boost::units::si::surface_density);
173 
178  using Angle = PLAYRHO_QUANTITY(boost::units::si::plane_angle);
179 
188  using AngularVelocity = PLAYRHO_QUANTITY(boost::units::si::angular_velocity);
189 
198  using AngularAcceleration = PLAYRHO_QUANTITY(boost::units::si::angular_acceleration);
199 
207  using Force = PLAYRHO_QUANTITY(boost::units::si::force);
208 
218  using Torque = PLAYRHO_QUANTITY(boost::units::si::torque);
219 
226  using SecondMomentOfArea = PLAYRHO_QUANTITY(boost::units::si::second_moment_of_area);
227 
237  using RotInertia = PLAYRHO_QUANTITY(boost::units::si::moment_of_inertia);
238 
245  using InvRotInertia = PLAYRHO_QUANTITY(boost::units::si::inverse_moment_of_inertia);
246 
256  using Momentum = PLAYRHO_QUANTITY(boost::units::si::momentum);
257 
267  using AngularMomentum = PLAYRHO_QUANTITY(boost::units::si::angular_momentum);
268 
270 
278 
283  PLAYRHO_CONSTEXPR const auto Second = PLAYRHO_UNIT(Time, boost::units::si::second);
284 
288 
293  PLAYRHO_CONSTEXPR const auto Hertz = PLAYRHO_UNIT(Frequency, boost::units::si::hertz);
294 
300  PLAYRHO_CONSTEXPR const auto Meter = PLAYRHO_UNIT(Length, boost::units::si::meter);
301 
305  boost::units::si::meter_per_second);
306 
310  boost::units::si::meter_per_second_squared);
311 
316  PLAYRHO_CONSTEXPR const auto Kilogram = PLAYRHO_UNIT(Mass, boost::units::si::kilogram);
317 
320  PLAYRHO_CONSTEXPR const auto SquareMeter = PLAYRHO_UNIT(Area, boost::units::si::square_meter);
321 
324 
328  boost::units::si::kilogram_per_square_meter);
329 
333  PLAYRHO_CONSTEXPR const auto Radian = PLAYRHO_UNIT(Angle, boost::units::si::radian);
334 
338  PLAYRHO_CONSTEXPR const auto Degree = Angle{Radian * Pi / Real{180}};
339 
344 
349  boost::units::si::radian_per_second);
350 
355 
360 
365 
368  PLAYRHO_CONSTEXPR const auto Newton = PLAYRHO_UNIT(Force, boost::units::si::newton);
369 
373  PLAYRHO_CONSTEXPR const auto NewtonMeter = PLAYRHO_UNIT(Torque, boost::units::si::newton_meter);
374 
379 
384 
389 
391 
398 
401  PLAYRHO_CONSTEXPR inline Mass operator"" _g(unsigned long long int v) noexcept
402  {
403  return static_cast<Real>(v) * (Kilogram / Kilo);
404  }
405 
408  PLAYRHO_CONSTEXPR inline Mass operator"" _g(long double v) noexcept
409  {
410  return static_cast<Real>(v) * (Kilogram / Kilo);
411  }
412 
416  PLAYRHO_CONSTEXPR inline Mass operator"" _kg(unsigned long long int v) noexcept
417  {
418  return static_cast<Real>(v) * Kilogram;
419  }
420 
424  PLAYRHO_CONSTEXPR inline Mass operator"" _kg(long double v) noexcept
425  {
426  return static_cast<Real>(v) * Kilogram;
427  }
428 
431  PLAYRHO_CONSTEXPR inline Mass operator"" _Pg(unsigned long long int v) noexcept
432  {
433  return static_cast<Real>(v) * Peta * (Kilogram / Kilo);
434  }
435 
438  PLAYRHO_CONSTEXPR inline Mass operator"" _Pg(long double v) noexcept
439  {
440  return static_cast<Real>(v) * Peta * (Kilogram / Kilo);
441  }
442 
445  PLAYRHO_CONSTEXPR inline Mass operator"" _Yg(unsigned long long int v) noexcept
446  {
447  return static_cast<Real>(v) * Yotta * (Kilogram / Kilo);
448  }
449 
452  PLAYRHO_CONSTEXPR inline Mass operator"" _Yg(long double v) noexcept
453  {
454  return static_cast<Real>(v) * Yotta * (Kilogram / Kilo);
455  }
456 
460  PLAYRHO_CONSTEXPR inline Length operator"" _m(unsigned long long int v) noexcept
461  {
462  return static_cast<Real>(v) * Meter;
463  }
464 
468  PLAYRHO_CONSTEXPR inline Length operator"" _m(long double v) noexcept
469  {
470  return static_cast<Real>(v) * Meter;
471  }
472 
475  PLAYRHO_CONSTEXPR inline Length operator"" _dm(unsigned long long int v) noexcept
476  {
477  return static_cast<Real>(v) * Deci * Meter;
478  }
479 
482  PLAYRHO_CONSTEXPR inline Length operator"" _dm(long double v) noexcept
483  {
484  return static_cast<Real>(v) * Deci * Meter;
485  }
486 
489  PLAYRHO_CONSTEXPR inline Length operator"" _cm(unsigned long long int v) noexcept
490  {
491  return static_cast<Real>(v) * Centi * Meter;
492  }
493 
496  PLAYRHO_CONSTEXPR inline Length operator"" _cm(long double v) noexcept
497  {
498  return static_cast<Real>(v) * Centi * Meter;
499  }
500 
503  PLAYRHO_CONSTEXPR inline Length operator"" _Gm (unsigned long long int v) noexcept
504  {
505  return static_cast<Real>(v) * Giga * Meter;
506  }
507 
510  PLAYRHO_CONSTEXPR inline Length operator"" _Gm (long double v) noexcept
511  {
512  return static_cast<Real>(v) * Giga * Meter;
513  }
514 
517  PLAYRHO_CONSTEXPR inline Length operator"" _Mm (unsigned long long int v) noexcept
518  {
519  return static_cast<Real>(v) * Mega * Meter;
520  }
521 
524  PLAYRHO_CONSTEXPR inline Length operator"" _Mm (long double v) noexcept
525  {
526  return static_cast<Real>(v) * Mega * Meter;
527  }
528 
531  PLAYRHO_CONSTEXPR inline Length operator"" _km (unsigned long long int v) noexcept
532  {
533  return static_cast<Real>(v) * Kilo * Meter;
534  }
535 
538  PLAYRHO_CONSTEXPR inline Length operator"" _km (long double v) noexcept
539  {
540  return static_cast<Real>(v) * Kilo * Meter;
541  }
542 
546  PLAYRHO_CONSTEXPR inline Time operator"" _s(unsigned long long int v) noexcept
547  {
548  return static_cast<Real>(v) * Second;
549  }
550 
554  PLAYRHO_CONSTEXPR inline Time operator"" _s(long double v) noexcept
555  {
556  return static_cast<Real>(v) * Second;
557  }
558 
561  PLAYRHO_CONSTEXPR inline Time operator"" _min(unsigned long long int v) noexcept
562  {
563  return static_cast<Real>(v) * 60 * Second;
564  }
565 
568  PLAYRHO_CONSTEXPR inline Time operator"" _min(long double v) noexcept
569  {
570  return static_cast<Real>(v) * 60 * Second;
571  }
572 
575  PLAYRHO_CONSTEXPR inline Time operator"" _h(unsigned long long int v) noexcept
576  {
577  return static_cast<Real>(v) * 60 * 60 * Second;
578  }
579 
582  PLAYRHO_CONSTEXPR inline Time operator"" _h(long double v) noexcept
583  {
584  return static_cast<Real>(v) * 60 * 60 * Second;
585  }
586 
589  PLAYRHO_CONSTEXPR inline Time operator"" _d(unsigned long long int v) noexcept
590  {
591  return static_cast<Real>(v) * 60 * 60 * 24 * Second;
592  }
593 
596  PLAYRHO_CONSTEXPR inline Time operator"" _d(long double v) noexcept
597  {
598  return static_cast<Real>(v) * 60 * 60 * 24 * Second;
599  }
600 
604  PLAYRHO_CONSTEXPR inline Angle operator"" _rad(unsigned long long int v) noexcept
605  {
606  return static_cast<Real>(v) * Radian;
607  }
608 
612  PLAYRHO_CONSTEXPR inline Angle operator"" _rad(long double v) noexcept
613  {
614  return static_cast<Real>(v) * Radian;
615  }
616 
620  PLAYRHO_CONSTEXPR inline Angle operator"" _deg(unsigned long long int v) noexcept
621  {
622  return static_cast<Real>(v) * Degree;
623  }
624 
628  PLAYRHO_CONSTEXPR inline Angle operator"" _deg(long double v) noexcept
629  {
630  return static_cast<Real>(v) * Degree;
631  }
632 
636  PLAYRHO_CONSTEXPR inline Force operator"" _N(unsigned long long int v) noexcept
637  {
638  return static_cast<Real>(v) * Newton;
639  }
640 
644  PLAYRHO_CONSTEXPR inline Force operator"" _N(long double v) noexcept
645  {
646  return static_cast<Real>(v) * Newton;
647  }
648 
651  PLAYRHO_CONSTEXPR inline Area operator"" _m2(unsigned long long int v) noexcept
652  {
653  return static_cast<Real>(v) * SquareMeter;
654  }
655 
658  PLAYRHO_CONSTEXPR inline Area operator"" _m2(long double v) noexcept
659  {
660  return static_cast<Real>(v) * SquareMeter;
661  }
662 
668  PLAYRHO_CONSTEXPR inline LinearVelocity operator"" _mps(unsigned long long int v) noexcept
669  {
670  return static_cast<Real>(v) * MeterPerSecond;
671  }
672 
678  PLAYRHO_CONSTEXPR inline LinearVelocity operator"" _mps(long double v) noexcept
679  {
680  return static_cast<Real>(v) * MeterPerSecond;
681  }
682 
686  PLAYRHO_CONSTEXPR inline LinearVelocity operator"" _kps(unsigned long long int v) noexcept
687  {
688  return static_cast<Real>(v) * Kilo * MeterPerSecond;
689  }
690 
694  PLAYRHO_CONSTEXPR inline LinearVelocity operator"" _kps(long double v) noexcept
695  {
696  return static_cast<Real>(v) * Kilo * MeterPerSecond;
697  }
698 
702  PLAYRHO_CONSTEXPR inline LinearAcceleration operator"" _mps2(unsigned long long int v) noexcept
703  {
704  return static_cast<Real>(v) * MeterPerSquareSecond;
705  }
706 
710  PLAYRHO_CONSTEXPR inline LinearAcceleration operator"" _mps2(long double v) noexcept
711  {
712  return static_cast<Real>(v) * MeterPerSquareSecond;
713  }
714 
718  PLAYRHO_CONSTEXPR inline Frequency operator"" _Hz(unsigned long long int v) noexcept
719  {
720  return static_cast<Real>(v) * Hertz;
721  }
722 
726  PLAYRHO_CONSTEXPR inline Frequency operator"" _Hz(long double v) noexcept
727  {
728  return static_cast<Real>(v) * Hertz;
729  }
730 
734  PLAYRHO_CONSTEXPR inline Torque operator"" _Nm(unsigned long long int v) noexcept
735  {
736  return static_cast<Real>(v) * NewtonMeter;
737  }
738 
742  PLAYRHO_CONSTEXPR inline Torque operator"" _Nm(long double v) noexcept
743  {
744  return static_cast<Real>(v) * NewtonMeter;
745  }
746 
750  PLAYRHO_CONSTEXPR inline Momentum operator"" _Ns(unsigned long long int v) noexcept
751  {
752  return static_cast<Real>(v) * NewtonSecond;
753  }
754 
758  PLAYRHO_CONSTEXPR inline Momentum operator"" _Ns(long double v) noexcept
759  {
760  return static_cast<Real>(v) * NewtonSecond;
761  }
762 
764  PLAYRHO_CONSTEXPR inline AreaDensity operator"" _kgpm2(unsigned long long int v) noexcept
765  {
766  return static_cast<Real>(v) * KilogramPerSquareMeter;
767  }
768 
770  PLAYRHO_CONSTEXPR inline AreaDensity operator"" _kgpm2(long double v) noexcept
771  {
772  return static_cast<Real>(v) * KilogramPerSquareMeter;
773  }
774 
777  PLAYRHO_CONSTEXPR inline AngularVelocity operator"" _rpm(unsigned long long int v) noexcept
778  {
779  return static_cast<Real>(v) * RevolutionsPerMinute;
780  }
781 
784  PLAYRHO_CONSTEXPR inline AngularVelocity operator"" _rpm(long double v) noexcept
785  {
786  return static_cast<Real>(v) * RevolutionsPerMinute;
787  }
788 
790 
792  PLAYRHO_CONSTEXPR inline Real StripUnit(const Real value)
793  {
794  return value;
795  }
796 
802 
810 
815  PLAYRHO_CONSTEXPR const auto BigG = Real{6.67408e-11f} * CubicMeter / (Kilogram * SquareSecond);
816 
818 
819 #if defined(USE_BOOST_UNITS)
822  using boost::units::cos;
823  using boost::units::sin;
824 
825  // Don't use boost's hypot since it does type promotion which is problematic.
826  // using boost::units::hypot;
827 
832  template<class Unit>
833  inline auto
834  hypot(const boost::units::quantity<Unit,Real>& x, const boost::units::quantity<Unit,Real>& y)
835  {
836  using std::hypot;
837  return boost::units::quantity<Unit,Real>::from_value(hypot(x.value(), y.value()));
838  }
839 
845  template<class Unit>
846  inline auto
847  sqrt(const boost::units::quantity<Unit,Real>& q)
848  {
849  using std::sqrt;
850  using quantity_type = typename boost::units::root_typeof_helper<
851  boost::units::quantity<Unit,Real>,
852  boost::units::static_rational<2>
853  >::type;
854  using unit_type = typename quantity_type::unit_type;
855 
856  return boost::units::quantity<unit_type, Real>::from_value(sqrt(q.value()));
857  }
858 
860  template <class Y>
861  inline auto AlmostZero(const boost::units::quantity<Y, Real> v)
862  {
863  return abs(v) < std::numeric_limits<boost::units::quantity<Y, Real>>::min();
864  }
865 
867  template<class Unit,class Y>
868  PLAYRHO_CONSTEXPR inline auto StripUnit(const boost::units::quantity<Unit, Y> source)
869  {
870  return source.value();
871  }
872 
874  template <>
875  PLAYRHO_CONSTEXPR inline Angle GetInvalid() noexcept
876  {
877  return GetInvalid<Real>() * Radian;
878  }
879 
881  template <>
882  PLAYRHO_CONSTEXPR inline Frequency GetInvalid() noexcept
883  {
884  return GetInvalid<Real>() * Hertz;
885  }
886 
888  template <>
890  {
891  return GetInvalid<Real>() * RadianPerSecond;
892  }
893 
895  template <>
896  PLAYRHO_CONSTEXPR inline Time GetInvalid() noexcept
897  {
898  return GetInvalid<Real>() * Second;
899  }
900 
902  template <>
903  PLAYRHO_CONSTEXPR inline Length GetInvalid() noexcept
904  {
905  return GetInvalid<Real>() * Meter;
906  }
907 
909  template <>
910  PLAYRHO_CONSTEXPR inline Mass GetInvalid() noexcept
911  {
912  return GetInvalid<Real>() * Kilogram;
913  }
914 
916  template <>
917  PLAYRHO_CONSTEXPR inline InvMass GetInvalid() noexcept
918  {
919  return GetInvalid<Real>() / Kilogram;
920  }
921 
923  template <>
924  PLAYRHO_CONSTEXPR inline Momentum GetInvalid() noexcept
925  {
926  return GetInvalid<Real>() * Kilogram * MeterPerSecond;
927  }
928 
930  template <>
931  PLAYRHO_CONSTEXPR inline Force GetInvalid() noexcept
932  {
933  return GetInvalid<Real>() * Newton;
934  }
935 
937  template <>
938  PLAYRHO_CONSTEXPR inline Torque GetInvalid() noexcept
939  {
940  return GetInvalid<Real>() * NewtonMeter;
941  }
942 
944  template <>
946  {
947  return GetInvalid<Real>() * MeterPerSecond;
948  }
949 
951  template <>
953  {
954  return GetInvalid<Real>() * MeterPerSquareSecond;
955  }
956 
958  template <>
960  {
961  return GetInvalid<Real>() * RadianPerSquareSecond;
962  }
963 
965  template <>
966  PLAYRHO_CONSTEXPR inline RotInertia GetInvalid() noexcept
967  {
968  // RotInertia is L^2 M QP^-2
969  return GetInvalid<Real>() * SquareMeter * Kilogram / SquareRadian;
970  }
971 
972 #endif // defined(USE_BOOST_UNITS)
973 
974 } // namespace playrho
975 
976 #if defined(USE_BOOST_UNITS)
977 namespace boost {
978 namespace units {
979 
980 // Define division and multiplication templated operators in boost::units namespace since
981 // boost::units is the consistent namespace of operands for these and this aids with
982 // argument dependent lookup (ADL).
983 //
984 // Note that while boost::units already defines division and multiplication operator support,
985 // that's only for division or multiplication with the same type that the quantity is based
986 // on. For example when Real is float, Length{0.0f} * 2.0f is already supported but
987 // Length{0.0f} * 2 is not.
988 
997 template <class Dimension, typename X, typename = std::enable_if_t<
998  playrho::IsArithmetic<X>::value && !std::is_same<X, playrho::Real>::value &&
999  std::is_same<decltype(playrho::Real{} / X{}), playrho::Real>::value >
1000 >
1001 PLAYRHO_CONSTEXPR inline auto operator/ (quantity<Dimension, playrho::Real> lhs, X rhs)
1002 {
1003  return lhs / playrho::Real(rhs);
1004 }
1005 
1006 template <class Dimension, typename X, typename = std::enable_if_t<
1007  playrho::IsArithmetic<X>::value && !std::is_same<X, playrho::Real>::value &&
1008  std::is_same<decltype(X{} / playrho::Real{}), playrho::Real>::value >
1009 >
1010 PLAYRHO_CONSTEXPR inline auto operator/ (X lhs, quantity<Dimension, playrho::Real> rhs)
1011 {
1012  return playrho::Real(lhs) / rhs;
1013 }
1014 
1023 template <class Dimension, typename X, typename = std::enable_if_t<
1024  playrho::IsArithmetic<X>::value && !std::is_same<X, playrho::Real>::value &&
1025  std::is_same<decltype(playrho::Real{} * X{}), playrho::Real>::value> >
1026 PLAYRHO_CONSTEXPR inline auto operator* (quantity<Dimension, playrho::Real> lhs, X rhs)
1027 {
1028  return lhs * playrho::Real(rhs);
1029 }
1030 
1039 template <class Dimension, typename X, typename = std::enable_if_t<
1040  playrho::IsArithmetic<X>::value && !std::is_same<X, playrho::Real>::value &&
1041  std::is_same<decltype(playrho::Real{} * X{}), playrho::Real>::value> >
1042 PLAYRHO_CONSTEXPR inline auto operator* (X lhs, quantity<Dimension, playrho::Real> rhs)
1043 {
1044  return playrho::Real(lhs) * rhs;
1045 }
1046 
1047 } // namespace units
1048 } // namespace boost
1049 #endif // defined(USE_BOOST_UNITS)
1050 
1051 #undef PLAYRHO_QUANTITY
1052 #undef PLAYRHO_UNIT
1053 
1054 #endif // PLAYRHO_COMMON_UNITS_HPP