Math.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
22 #ifndef PLAYRHO_COMMON_MATH_HPP
23 #define PLAYRHO_COMMON_MATH_HPP
24 
27 #include <PlayRho/Common/Span.hpp>
35 #include <PlayRho/Common/Sweep.hpp>
38 
39 #include <cmath>
40 #include <vector>
41 #include <numeric>
42 
43 namespace playrho {
44 
45 // Import common standard mathematical functions into the playrho namespace...
46 using std::signbit;
47 using std::nextafter;
48 using std::trunc;
49 using std::fmod;
50 using std::isfinite;
51 using std::round;
52 using std::isnormal;
53 using std::isnan;
54 using std::hypot;
55 using std::cos;
56 using std::sin;
57 using std::atan2;
58 using std::sqrt;
59 using std::pow;
60 using std::abs;
61 
62 // Other templates.
63 
65 template <typename T>
66 PLAYRHO_CONSTEXPR inline auto& GetX(T& value)
67 {
68  return get<0>(value);
69 }
70 
72 template <typename T>
73 PLAYRHO_CONSTEXPR inline auto& GetY(T& value)
74 {
75  return get<1>(value);
76 }
77 
79 template <typename T>
80 PLAYRHO_CONSTEXPR inline auto& GetZ(T& value)
81 {
82  return get<2>(value);
83 }
84 
86 template <typename T>
87 PLAYRHO_CONSTEXPR inline auto GetX(const T& value)
88 {
89  return get<0>(value);
90 }
91 
93 template <typename T>
94 PLAYRHO_CONSTEXPR inline auto GetY(const T& value)
95 {
96  return get<1>(value);
97 }
98 
100 template <typename T>
101 PLAYRHO_CONSTEXPR inline auto GetZ(const T& value)
102 {
103  return get<2>(value);
104 }
105 
109 template <typename T>
110 PLAYRHO_CONSTEXPR inline std::enable_if_t<std::is_signed<T>::value, std::make_unsigned_t<T>>
111 MakeUnsigned(const T& arg) noexcept
112 {
113  return static_cast<std::make_unsigned_t<T>>(arg);
114 }
115 
117 template <typename T, LoValueCheck lo, HiValueCheck hi>
119 {
120  return StripUnit(v.get());
121 }
122 
128 
131 template <typename T, typename U>
132 PLAYRHO_CONSTEXPR inline U Secant(T target, U a1, T s1, U a2, T s2) noexcept
133 {
134  static_assert(IsArithmetic<T>::value && IsArithmetic<U>::value, "Arithmetic types required.");
135  return (a1 + (target - s1) * (a2 - a1) / (s2 - s1));
136 }
137 
140 template <typename T>
141 PLAYRHO_CONSTEXPR inline T Bisect(T a1, T a2) noexcept
142 {
143  return (a1 + a2) / 2;
144 }
145 
148 template <typename T>
149 PLAYRHO_CONSTEXPR inline bool IsOdd(T val) noexcept
150 {
151  static_assert(std::is_integral<T>::value, "Integral type required.");
152  return val % 2;
153 }
154 
156 template<class TYPE>
157 PLAYRHO_CONSTEXPR inline auto Square(TYPE t) noexcept { return t * t; }
158 
162 template<typename T>
163 inline auto Atan2(T y, T x)
164 {
165  return Angle{static_cast<Real>(atan2(StripUnit(y), StripUnit(x))) * Radian};
166 }
167 
169 template <typename T, typename = std::enable_if_t<
170  IsIterable<T>::value && IsAddable<decltype(*begin(std::declval<T>()))>::value
171  > >
172 inline auto Average(const T& span)
173 {
174  using value_type = decltype(*begin(std::declval<T>()));
175 
176  // Relies on C++11 zero initialization to zero initialize value_type.
177  // See: http://en.cppreference.com/w/cpp/language/zero_initialization
178  PLAYRHO_CONSTEXPR const auto zero = value_type{};
179  assert(zero * Real{2} == zero);
180 
181  // For C++17, switch from using std::accumulate to using std::reduce.
182  const auto sum = std::accumulate(begin(span), end(span), zero);
183  const auto count = std::max(size(span), std::size_t{1});
184  return sum / static_cast<Real>(count);
185 }
186 
188 template <typename T>
189 inline std::enable_if_t<IsArithmetic<T>::value, T> RoundOff(T value, unsigned precision = 100000)
190 {
191  const auto factor = static_cast<T>(precision);
192  return round(value * factor) / factor;
193 }
194 
196 inline Vec2 RoundOff(Vec2 value, std::uint32_t precision = 100000)
197 {
198  return Vec2{RoundOff(value[0], precision), RoundOff(value[1], precision)};
199 }
200 
203 template <typename T, std::size_t N>
205 {
206  auto result = Vector<T, N>{};
207  for (auto i = decltype(N){0}; i < N; ++i)
208  {
209  result[i] = abs(v[i]);
210  }
211  return result;
212 }
213 
215 inline d2::UnitVec abs(const d2::UnitVec& v) noexcept
216 {
217  return v.Absolute();
218 }
219 
224 template <typename T>
225 PLAYRHO_CONSTEXPR inline
226 std::enable_if_t<std::is_arithmetic<T>::value, bool> AlmostZero(T value)
227 {
228  return abs(value) < std::numeric_limits<T>::min();
229 }
230 
232 template <typename T>
233 PLAYRHO_CONSTEXPR inline
234 std::enable_if_t<std::is_floating_point<T>::value, bool> AlmostEqual(T x, T y, int ulp = 2)
235 {
236  // From http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon :
237  // "the machine epsilon has to be scaled to the magnitude of the values used
238  // and multiplied by the desired precision in ULPs (units in the last place)
239  // unless the result is subnormal".
240  // Where "subnormal" means almost zero.
241  //
242  return (abs(x - y) < (std::numeric_limits<T>::epsilon() * abs(x + y) * ulp)) || AlmostZero(x - y);
243 }
244 
248 template <typename T>
249 inline auto ModuloViaFmod(T dividend, T divisor) noexcept
250 {
251  // Note: modulo via std::fmod appears slower than via std::trunc.
252  return static_cast<T>(fmod(dividend, divisor));
253 }
254 
258 template <typename T>
259 inline auto ModuloViaTrunc(T dividend, T divisor) noexcept
260 {
261  const auto quotient = dividend / divisor;
262  const auto integer = static_cast<T>(trunc(quotient));
263  const auto remainder = quotient - integer;
264  return remainder * divisor;
265 }
266 
270 inline Angle GetNormalized(Angle value) noexcept
271 {
272  PLAYRHO_CONSTEXPR const auto oneRotationInRadians = Real{2 * Pi};
273  auto angleInRadians = Real{value / Radian};
274 #if defined(NORMALIZE_ANGLE_VIA_FMOD)
275  // Note: std::fmod appears slower than std::trunc.
276  // See Benchmark ModuloViaFmod for data.
277  angleInRadians = ModuloViaFmod(angleInRadians, oneRotationInRadians);
278 #else
279  // Note: std::trunc appears more than twice as fast as std::fmod.
280  // See Benchmark ModuloViaTrunc for data.
281  angleInRadians = ModuloViaTrunc(angleInRadians, oneRotationInRadians);
282 #endif
283  if (angleInRadians > Pi)
284  {
285  // 190_deg becomes 190_deg - 360_deg = -170_deg
286  angleInRadians -= Pi * 2;
287  }
288  else if (angleInRadians < -Pi)
289  {
290  // -200_deg becomes -200_deg + 360_deg = 100_deg
291  angleInRadians += Pi * 2;
292  }
293  return angleInRadians * Radian;
294 }
295 
298 template <class T>
299 inline Angle GetAngle(const Vector2<T> value)
300 {
301  return Atan2(GetY(value), GetX(value));
302 }
303 
307 template <typename T>
308 PLAYRHO_CONSTEXPR inline
309 auto GetMagnitudeSquared(T value) noexcept
310 {
311  using VT = typename T::value_type;
312  using OT = decltype(VT{} * VT{});
313  auto result = OT{};
314  for (auto&& e: value)
315  {
316  result += Square(e);
317  }
318  return result;
319 }
320 
323 template <typename T>
324 inline auto GetMagnitude(T value)
325 {
326  return sqrt(GetMagnitudeSquared(value));
327 }
328 
353 template <typename T1, typename T2>
354 PLAYRHO_CONSTEXPR inline auto Dot(const T1 a, const T2 b) noexcept
355 {
356  static_assert(std::tuple_size<T1>::value == std::tuple_size<T2>::value,
357  "Dot only for same tuple-like sized types");
358  using VT1 = typename T1::value_type;
359  using VT2 = typename T2::value_type;
360  using OT = decltype(VT1{} * VT2{});
361  auto result = OT{};
362  const auto numElements = size(a);
363  for (auto i = decltype(numElements){0}; i < numElements; ++i)
364  {
365  result += a[i] * b[i];
366  }
367  return result;
368 }
369 
397 template <class T1, class T2, std::enable_if_t<
398  std::tuple_size<T1>::value == 2 && std::tuple_size<T2>::value == 2, int> = 0>
399 PLAYRHO_CONSTEXPR inline auto Cross(T1 a, T2 b) noexcept
400 {
401  assert(isfinite(StripUnit(get<0>(a))));
402  assert(isfinite(StripUnit(get<1>(a))));
403  assert(isfinite(StripUnit(get<0>(b))));
404  assert(isfinite(StripUnit(get<1>(b))));
405 
406  // Both vectors of same direction...
407  // If a = Vec2{1, 2} and b = Vec2{1, 2} then: a x b = 1 * 2 - 2 * 1 = 0.
408  // If a = Vec2{1, 2} and b = Vec2{2, 4} then: a x b = 1 * 4 - 2 * 2 = 0.
409  //
410  // Vectors at +/- 90 degrees of each other...
411  // If a = Vec2{1, 2} and b = Vec2{-2, 1} then: a x b = 1 * 1 - 2 * (-2) = 1 + 4 = 5.
412  // If a = Vec2{1, 2} and b = Vec2{2, -1} then: a x b = 1 * (-1) - 2 * 2 = -1 - 4 = -5.
413  //
414  // Vectors between 0 and 180 degrees of each other excluding 90 degrees...
415  // If a = Vec2{1, 2} and b = Vec2{-1, 2} then: a x b = 1 * 2 - 2 * (-1) = 2 + 2 = 4.
416  const auto minuend = get<0>(a) * get<1>(b);
417  const auto subtrahend = get<1>(a) * get<0>(b);
418  assert(isfinite(StripUnit(minuend)));
419  assert(isfinite(StripUnit(subtrahend)));
420  return minuend - subtrahend;
421 }
422 
429 template <class T1, class T2, std::enable_if_t<
430  std::tuple_size<T1>::value == 3 && std::tuple_size<T2>::value == 3, int> = 0>
431 PLAYRHO_CONSTEXPR inline auto Cross(T1 a, T2 b) noexcept
432 {
433  assert(isfinite(get<0>(a)));
434  assert(isfinite(get<1>(a)));
435  assert(isfinite(get<2>(a)));
436  assert(isfinite(get<0>(b)));
437  assert(isfinite(get<1>(b)));
438  assert(isfinite(get<2>(b)));
439 
440  using OT = decltype(get<0>(a) * get<0>(b));
441  return Vector<OT, 3>{
442  GetY(a) * GetZ(b) - GetZ(a) * GetY(b),
443  GetZ(a) * GetX(b) - GetX(a) * GetZ(b),
444  GetX(a) * GetY(b) - GetY(a) * GetX(b)
445  };
446 }
447 
450 template <typename T, typename U>
451 PLAYRHO_CONSTEXPR inline auto Solve(const Matrix22<U> mat, const Vector2<T> b) noexcept
452 {
453  const auto cp = Cross(get<0>(mat), get<1>(mat));
454  const auto inverseCp = Real{1} / cp;
455  using OutType = decltype((U{} * T{}) / cp);
456  return (!AlmostZero(StripUnit(cp)))?
458  (get<1>(mat)[1] * b[0] - get<1>(mat)[0] * b[1]) * inverseCp,
459  (get<0>(mat)[0] * b[1] - get<0>(mat)[1] * b[0]) * inverseCp
460  }: Vector2<OutType>{};
461 }
462 
464 template <class IN_TYPE>
465 PLAYRHO_CONSTEXPR inline auto Invert(const Matrix22<IN_TYPE> value) noexcept
466 {
467  const auto cp = Cross(get<0>(value), get<1>(value));
468  using OutType = decltype(get<0>(value)[0] / cp);
469  const auto inverseCp = Real{1} / cp;
470  return (!AlmostZero(StripUnit(cp)))?
472  Vector2<OutType>{ get<1>(get<1>(value)) * inverseCp, -get<1>(get<0>(value)) * inverseCp},
473  Vector2<OutType>{-get<0>(get<1>(value)) * inverseCp, get<0>(get<0>(value)) * inverseCp}
474  }:
476 }
477 
480 PLAYRHO_CONSTEXPR inline Vec3 Solve33(const Mat33& mat, const Vec3 b) noexcept
481 {
482  const auto dp = Dot(GetX(mat), Cross(GetY(mat), GetZ(mat)));
483  const auto det = (dp != 0)? Real{1} / dp: dp;
484  const auto x = det * Dot(b, Cross(GetY(mat), GetZ(mat)));
485  const auto y = det * Dot(GetX(mat), Cross(b, GetZ(mat)));
486  const auto z = det * Dot(GetX(mat), Cross(GetY(mat), b));
487  return Vec3{x, y, z};
488 }
489 
493 template <typename T>
494 PLAYRHO_CONSTEXPR inline T Solve22(const Mat33& mat, const T b) noexcept
495 {
496  const auto cp = GetX(GetX(mat)) * GetY(GetY(mat)) - GetX(GetY(mat)) * GetY(GetX(mat));
497  const auto det = (cp != 0)? Real{1} / cp: cp;
498  const auto x = det * (GetY(GetY(mat)) * GetX(b) - GetX(GetY(mat)) * GetY(b));
499  const auto y = det * (GetX(GetX(mat)) * GetY(b) - GetY(GetX(mat)) * GetX(b));
500  return T{x, y};
501 }
502 
505 PLAYRHO_CONSTEXPR inline Mat33 GetInverse22(const Mat33& value) noexcept
506 {
507  const auto a = GetX(GetX(value)), b = GetX(GetY(value)), c = GetY(GetX(value)), d = GetY(GetY(value));
508  auto det = (a * d) - (b * c);
509  if (det != Real{0})
510  {
511  det = Real{1} / det;
512  }
513  return Mat33{Vec3{det * d, -det * c, Real{0}}, Vec3{-det * b, det * a, 0}, Vec3{0, 0, 0}};
514 }
515 
518 PLAYRHO_CONSTEXPR inline Mat33 GetSymInverse33(const Mat33& value) noexcept
519 {
520  auto det = Dot(GetX(value), Cross(GetY(value), GetZ(value)));
521  if (det != Real{0})
522  {
523  det = Real{1} / det;
524  }
525 
526  const auto a11 = GetX(GetX(value)), a12 = GetX(GetY(value)), a13 = GetX(GetZ(value));
527  const auto a22 = GetY(GetY(value)), a23 = GetY(GetZ(value));
528  const auto a33 = GetZ(GetZ(value));
529 
530  const auto ex_y = det * (a13 * a23 - a12 * a33);
531  const auto ey_z = det * (a13 * a12 - a11 * a23);
532  const auto ex_z = det * (a12 * a23 - a13 * a22);
533 
534  return Mat33{
535  Vec3{det * (a22 * a33 - a23 * a23), ex_y, ex_z},
536  Vec3{ex_y, det * (a11 * a33 - a13 * a13), ey_z},
537  Vec3{ex_z, ey_z, det * (a11 * a22 - a12 * a12)}
538  };
539 }
540 
546 template <class T>
547 PLAYRHO_CONSTEXPR inline auto GetRevPerpendicular(const T vector) noexcept
548 {
549  // See http://mathworld.wolfram.com/PerpendicularVector.html
550  return T{-GetY(vector), GetX(vector)};
551 }
552 
558 template <class T>
559 PLAYRHO_CONSTEXPR inline auto GetFwdPerpendicular(const T vector) noexcept
560 {
561  // See http://mathworld.wolfram.com/PerpendicularVector.html
562  return T{GetY(vector), -GetX(vector)};
563 }
564 
569 template <std::size_t M, typename T1, std::size_t N, typename T2>
570 PLAYRHO_CONSTEXPR inline auto Transform(const Vector<T1, M> v, const Matrix<T2, M, N>& m) noexcept
571 {
572  return m * v;
573 }
574 
576 PLAYRHO_CONSTEXPR inline Vec2 Transform(const Vec2 v, const Mat33& A) noexcept
577 {
578  return Vec2{
579  get<0>(get<0>(A)) * v[0] + get<0>(get<1>(A)) * v[1],
580  get<1>(get<0>(A)) * v[0] + get<1>(get<1>(A)) * v[1]
581  };
582 }
583 
586 PLAYRHO_CONSTEXPR inline Vec2 InverseTransform(const Vec2 v, const Mat22& A) noexcept
587 {
588  return Vec2{Dot(v, GetX(A)), Dot(v, GetY(A))};
589 }
590 
592 PLAYRHO_CONSTEXPR inline Mat22 MulT(const Mat22& A, const Mat22& B) noexcept
593 {
594  const auto c1 = Vec2{Dot(GetX(A), GetX(B)), Dot(GetY(A), GetX(B))};
595  const auto c2 = Vec2{Dot(GetX(A), GetY(B)), Dot(GetY(A), GetY(B))};
596  return Mat22{c1, c2};
597 }
598 
600 inline Mat22 abs(const Mat22& A)
601 {
602  return Mat22{abs(GetX(A)), abs(GetY(A))};
603 }
604 
611 inline std::uint64_t NextPowerOfTwo(std::uint64_t x)
612 {
613  x |= (x >> 1u);
614  x |= (x >> 2u);
615  x |= (x >> 4u);
616  x |= (x >> 8u);
617  x |= (x >> 16u);
618  x |= (x >> 32u);
619  return x + 1;
620 }
621 
623 inline Real Normalize(Vec2& vector)
624 {
625  const auto length = GetMagnitude(vector);
626  if (!AlmostZero(length))
627  {
628  const auto invLength = Real{1} / length;
629  vector[0] *= invLength;
630  vector[1] *= invLength;
631  return length;
632  }
633  return 0;
634 }
635 
639 Length2 ComputeCentroid(const Span<const Length2>& vertices);
640 
642 template <typename T>
643 PLAYRHO_CONSTEXPR inline T GetModuloNext(T value, T count) noexcept
644 {
645  assert(value < count);
646  return (value + 1) % count;
647 }
648 
650 template <typename T>
651 PLAYRHO_CONSTEXPR inline T GetModuloPrev(T value, T count) noexcept
652 {
653  assert(value < count);
654  return (value? value: count) - 1;
655 }
656 
662 Angle GetDelta(Angle a1, Angle a2) noexcept;
663 
667 {
668  return (a1 > a2)? 360_deg - (a1 - a2): a2 - a1;
669 }
670 
672 std::vector<Length2> GetCircleVertices(Length radius, unsigned slices,
673  Angle start = 0_deg, Real turns = Real{1});
674 
676 NonNegative<Area> GetAreaOfCircle(Length radius);
677 
682 NonNegative<Area> GetAreaOfPolygon(Span<const Length2> vertices);
683 
690 SecondMomentOfArea GetPolarMoment(Span<const Length2> vertices);
691 
693 
694 namespace d2 {
695 
698 {
699  return Vec2{get<0>(value), get<1>(value)};
700 }
701 
703 inline Angle GetAngle(const UnitVec value)
704 {
705  return Atan2(GetY(value), GetX(value));
706 }
707 
709 template <class T, LoValueCheck lo, HiValueCheck hi>
711 {
712  return Vector2<T>{u.GetX() * s, u.GetY() * T{s}};
713 }
714 
716 template <class T>
717 PLAYRHO_CONSTEXPR inline Vector2<T> operator* (const T s, const UnitVec u) noexcept
718 {
719  return Vector2<T>{u.GetX() * s, u.GetY() * s};
720 }
721 
723 template <class T, LoValueCheck lo, HiValueCheck hi>
725 {
726  return Vector2<T>{u.GetX() * s, u.GetY() * T{s}};
727 }
728 
730 template <class T>
731 PLAYRHO_CONSTEXPR inline Vector2<T> operator* (const UnitVec u, const T s) noexcept
732 {
733  return Vector2<T>{u.GetX() * s, u.GetY() * s};
734 }
735 
738 {
739  const auto inverseS = Real{1} / s;
740  return Vec2{GetX(u) * inverseS, GetY(u) * inverseS};
741 }
742 
748 template <class T>
749 PLAYRHO_CONSTEXPR inline auto Rotate(const Vector2<T> vector, const UnitVec& angle) noexcept
750 {
751  const auto newX = (GetX(angle) * GetX(vector)) - (GetY(angle) * GetY(vector));
752  const auto newY = (GetY(angle) * GetX(vector)) + (GetX(angle) * GetY(vector));
753  return Vector2<T>{newX, newY};
754 }
755 
763 template <class T>
764 PLAYRHO_CONSTEXPR inline auto InverseRotate(const Vector2<T> vector, const UnitVec& angle) noexcept
765 {
766  const auto newX = (GetX(angle) * GetX(vector)) + (GetY(angle) * GetY(vector));
767  const auto newY = (GetX(angle) * GetY(vector)) - (GetY(angle) * GetX(vector));
768  return Vector2<T>{newX, newY};
769 }
770 
777 template <class T>
779 {
780  return std::get<0>(UnitVec::Get(StripUnit(GetX(value)), StripUnit(GetY(value)), fallback));
781 }
782 
786 inline Position GetNormalized(const Position& val) noexcept
787 {
788  return Position{val.linear, playrho::GetNormalized(val.angular)};
789 }
790 
796 inline Sweep GetNormalized(Sweep sweep) noexcept
797 {
798  const auto pos0a = playrho::GetNormalized(sweep.pos0.angular);
799  const auto d = sweep.pos0.angular - pos0a;
800  sweep.pos0.angular = pos0a;
801  sweep.pos1.angular -= d;
802  return sweep;
803 }
804 
816 PLAYRHO_CONSTEXPR inline Length2 Transform(const Length2 v, const Transformation xfm) noexcept
817 {
818  return Rotate(v, xfm.q) + xfm.p;
819 }
820 
832 {
833  const auto v2 = v - T.p;
834  return InverseRotate(v2, T.q);
835 }
836 
841 {
842  return Transformation{A.p + Rotate(B.p, A.q), A.q.Rotate(B.q)};
843 }
844 
849 {
850  const auto dp = B.p - A.p;
851  return Transformation{InverseRotate(dp, A.q), B.q.Rotate(A.q.FlipY())};
852 }
853 
856  const Length2 localCtr) noexcept
857 {
858  assert(IsValid(rot));
859  return Transformation{ctr - (Rotate(localCtr, rot)), rot};
860 }
861 
863 inline Transformation GetTransformation(const Position pos, const Length2 local_ctr) noexcept
864 {
865  assert(IsValid(pos));
866  assert(IsValid(local_ctr));
867  return GetTransformation(pos.linear, UnitVec::Get(pos.angular), local_ctr);
868 }
869 
874 inline Transformation GetTransformation(const Sweep& sweep, const Real beta) noexcept
875 {
876  assert(beta >= 0);
877  assert(beta <= 1);
878  return GetTransformation(GetPosition(sweep.pos0, sweep.pos1, beta), sweep.GetLocalCenter());
879 }
880 
886 inline Transformation GetTransform0(const Sweep& sweep) noexcept
887 {
888  return GetTransformation(sweep.pos0, sweep.GetLocalCenter());
889 }
890 
896 inline Transformation GetTransform1(const Sweep& sweep) noexcept
897 {
898  return GetTransformation(sweep.pos1, sweep.GetLocalCenter());
899 }
900 
904 LinearVelocity2 GetContactRelVelocity(const Velocity velA, const Length2 relA,
905  const Velocity velB, const Length2 relB) noexcept;
906 
908 inline bool IsUnderActive(Velocity velocity,
909  LinearVelocity linSleepTol, AngularVelocity angSleepTol) noexcept
910 {
911  const auto linVelSquared = GetMagnitudeSquared(velocity.linear);
912  const auto angVelSquared = Square(velocity.angular);
913  return (angVelSquared <= Square(angSleepTol)) && (linVelSquared <= Square(linSleepTol));
914 }
915 
920 {
921  constexpr auto TupleSize = std::tuple_size<decltype(axis)>::value;
922  constexpr auto NumRows = TupleSize;
923  constexpr auto NumCols = TupleSize;
924  auto result = Matrix<Real, NumRows, NumCols>{};
925  for (auto row = decltype(NumRows){0}; row < NumRows; ++row)
926  {
927  for (auto col = decltype(NumCols){0}; col < NumCols; ++col)
928  {
929  result[row][col] = ((row == col)? Real{1}: Real{0}) - axis[row] * axis[col] * 2;
930  }
931  }
932  return result;
933 }
934 
935 } // namespace d2
936 } // namespace playrho
937 
938 #endif // PLAYRHO_COMMON_MATH_HPP