UnitVec.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 
21 #ifndef PLAYRHO_COMMON_UNITVEC2_HPP
22 #define PLAYRHO_COMMON_UNITVEC2_HPP
23 
26 
28 #include <PlayRho/Common/Units.hpp>
30 
31 #include <cstdlib>
32 #include <iostream>
33 #include <utility>
34 #include <type_traits>
35 
36 namespace playrho {
37 
38 // Explicitly import needed functions into this namespace to avoid including the math
39 // header which itself expects UnitVec to already be defined.
40 using std::isnormal;
41 using std::sqrt;
42 using std::hypot;
43 using std::abs;
44 
45 namespace d2 {
46 
49 class UnitVec
50 {
51 public:
53  using value_type = Real;
54 
56  using size_type = std::size_t;
57 
59  using const_reference = const value_type&;
60 
62  using const_pointer = const value_type*;
63 
65  using const_iterator = const value_type*;
66 
68  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
69 
74  static PLAYRHO_CONSTEXPR inline UnitVec GetRight() noexcept { return UnitVec{1, 0}; }
75 
80  static PLAYRHO_CONSTEXPR inline UnitVec GetTop() noexcept { return UnitVec{0, 1}; }
81 
86  static PLAYRHO_CONSTEXPR inline UnitVec GetLeft() noexcept { return UnitVec{-1, 0}; }
87 
92  static PLAYRHO_CONSTEXPR inline UnitVec GetBottom() noexcept { return UnitVec{0, -1}; }
93 
95  static PLAYRHO_CONSTEXPR inline UnitVec GetZero() noexcept { return UnitVec{0, 0}; }
96 
99  static PLAYRHO_CONSTEXPR inline UnitVec GetTopRight() noexcept
100  {
101  // Note that 1/sqrt(2) == sqrt(2)/(sqrt(2)*sqrt(2)) == sqrt(2)/2
102  return UnitVec{+SquareRootTwo/Real(2), +SquareRootTwo/Real(2)};
103  }
104 
108  static PLAYRHO_CONSTEXPR inline UnitVec GetBottomRight() noexcept
109  {
110  // Note that 1/sqrt(2) == sqrt(2)/(sqrt(2)*sqrt(2)) == sqrt(2)/2
111  return UnitVec{+SquareRootTwo/Real(2), -SquareRootTwo/Real(2)};
112  }
113 
115  static PLAYRHO_CONSTEXPR inline UnitVec GetDefaultFallback() noexcept { return UnitVec{}; }
116 
121  template <typename T>
122  using PolarCoord = std::enable_if_t<IsArithmetic<T>::value, std::pair<UnitVec, T>>;
123 
125  template <typename T>
126  static PolarCoord<T> Get(const T x, const T y,
127  const UnitVec fallback = GetDefaultFallback()) noexcept
128  {
129  // Try the faster way first...
130  const auto magnitudeSquared = x * x + y * y;
131  if (isnormal(magnitudeSquared))
132  {
133  const auto magnitude = sqrt(magnitudeSquared);
134  assert(isnormal(magnitude));
135  const auto invMagnitude = Real{1} / magnitude;
136  return {UnitVec{value_type{x * invMagnitude}, value_type{y * invMagnitude}}, magnitude};
137  }
138 
139  // Failed the faster way, try the more accurate and robust way...
140  const auto magnitude = hypot(x, y);
141  if (isnormal(magnitude))
142  {
143  return std::make_pair(UnitVec{x / magnitude, y / magnitude}, magnitude);
144  }
145 
146  // Give up and return the fallback value.
147  return std::make_pair(fallback, T{0});
148  }
149 
156  static UnitVec Get(const Angle angle) noexcept;
157 
158  PLAYRHO_CONSTEXPR inline UnitVec() noexcept = default;
159 
161  PLAYRHO_CONSTEXPR inline size_type max_size() const noexcept { return size_type{2}; }
162 
164  PLAYRHO_CONSTEXPR inline size_type size() const noexcept { return size_type{2}; }
165 
168  PLAYRHO_CONSTEXPR inline bool empty() const noexcept { return false; }
169 
171  const_iterator begin() const noexcept { return const_iterator(m_elems); }
172 
174  const_iterator end() const noexcept { return const_iterator(m_elems + 2); }
175 
177  const_iterator cbegin() const noexcept { return begin(); }
178 
180  const_iterator cend() const noexcept { return end(); }
181 
184  {
185  return const_reverse_iterator{m_elems + 2};
186  }
187 
189  const_reverse_iterator crend() const noexcept
190  {
191  return const_reverse_iterator{m_elems};
192  }
193 
196  {
197  return crbegin();
198  }
199 
201  const_reverse_iterator rend() const noexcept
202  {
203  return crend();
204  }
205 
210  {
211  assert(pos < size());
212  return m_elems[pos];
213  }
214 
218  {
219  if (pos >= size())
220  {
221  throw InvalidArgument("Vector::at: position >= size()");
222  }
223  return m_elems[pos];
224  }
225 
227  PLAYRHO_CONSTEXPR inline const_pointer data() const noexcept
228  {
229  return m_elems;
230  }
231 
233  PLAYRHO_CONSTEXPR inline auto GetX() const noexcept { return m_elems[0]; }
234 
236  PLAYRHO_CONSTEXPR inline auto GetY() const noexcept { return m_elems[1]; }
237 
239  PLAYRHO_CONSTEXPR inline UnitVec FlipXY() const noexcept { return UnitVec{-GetX(), -GetY()}; }
240 
242  PLAYRHO_CONSTEXPR inline UnitVec FlipX() const noexcept { return UnitVec{-GetX(), GetY()}; }
243 
245  PLAYRHO_CONSTEXPR inline UnitVec FlipY() const noexcept { return UnitVec{GetX(), -GetY()}; }
246 
254  PLAYRHO_CONSTEXPR inline UnitVec Rotate(UnitVec amount) const noexcept
255  {
256  return UnitVec{GetX() * amount.GetX() - GetY() * amount.GetY(),
257  GetY() * amount.GetX() + GetX() * amount.GetY()};
258  }
259 
265  {
266  // See http://mathworld.wolfram.com/PerpendicularVector.html
267  return UnitVec{-GetY(), GetX()};
268  }
269 
275  {
276  // See http://mathworld.wolfram.com/PerpendicularVector.html
277  return UnitVec{GetY(), -GetX()};
278  }
279 
281  PLAYRHO_CONSTEXPR inline UnitVec operator-() const noexcept { return UnitVec{-GetX(), -GetY()}; }
282 
284  PLAYRHO_CONSTEXPR inline UnitVec operator+() const noexcept { return UnitVec{+GetX(), +GetY()}; }
285 
287  PLAYRHO_CONSTEXPR inline UnitVec Absolute() const noexcept
288  {
289  return UnitVec{abs(GetX()), abs(GetY())};
290  }
291 
292 private:
293 
295  PLAYRHO_CONSTEXPR inline UnitVec(value_type x, value_type y) noexcept : m_elems{x, y}
296  {
297  // Intentionally empty.
298  }
299 
300  value_type m_elems[2] = { value_type{0}, value_type{0} };
301 };
302 
303 // Free functions...
304 
306 PLAYRHO_CONSTEXPR inline UnitVec GetXAxis(UnitVec rot) noexcept { return rot; }
307 
310 PLAYRHO_CONSTEXPR inline UnitVec GetYAxis(UnitVec rot) noexcept { return rot.GetRevPerpendicular(); }
311 
313 PLAYRHO_CONSTEXPR inline bool operator==(const UnitVec a, const UnitVec b) noexcept
314 {
315  return (a.GetX() == b.GetX()) && (a.GetY() == b.GetY());
316 }
317 
319 PLAYRHO_CONSTEXPR inline bool operator!=(const UnitVec a, const UnitVec b) noexcept
320 {
321  return (a.GetX() != b.GetX()) || (a.GetY() != b.GetY());
322 }
323 
331 {
332  return vector.GetRevPerpendicular();
333 }
334 
341 {
342  return vector.GetFwdPerpendicular();
343 }
344 
348 PLAYRHO_CONSTEXPR inline UnitVec Rotate(const UnitVec vector, const UnitVec& angle) noexcept
349 {
350  return vector.Rotate(angle);
351 }
352 
354 PLAYRHO_CONSTEXPR inline UnitVec InverseRotate(const UnitVec vector, const UnitVec& angle) noexcept
355 {
356  return vector.Rotate(angle.FlipY());
357 }
358 
360 template <std::size_t I>
362 {
363  static_assert(I < 2, "Index out of bounds in playrho::get<> (playrho::UnitVec)");
364  switch (I)
365  {
366  case 0: return v.GetX();
367  case 1: return v.GetY();
368  }
369 }
370 
372 template <>
374 {
375  return v.GetX();
376 }
377 
379 template <>
381 {
382  return v.GetY();
383 }
384 
386 inline ::std::ostream& operator<<(::std::ostream& os, const UnitVec& value)
387 {
388  return os << "UnitVec(" << get<0>(value) << "," << get<1>(value) << ")";
389 }
390 
391 } // namespace d2
392 
394 template <> PLAYRHO_CONSTEXPR inline d2::UnitVec GetInvalid() noexcept { return d2::UnitVec{}; }
395 
397 template <> PLAYRHO_CONSTEXPR inline bool IsValid(const d2::UnitVec& value) noexcept
398 {
399  return IsValid(value.GetX()) && IsValid(value.GetY()) && (value != d2::UnitVec::GetZero());
400 }
401 
402 } // namespace playrho
403 
404 namespace std {
405 
407 template<>
408 class tuple_size< playrho::d2::UnitVec >: public std::integral_constant<std::size_t, 2> {};
409 
411 template<std::size_t I>
412 class tuple_element<I, playrho::d2::UnitVec>
413 {
414 public:
417 };
418 
419 } // namespace std
420 
421 #endif // PLAYRHO_COMMON_UNITVEC2_HPP