Ocular Engine
MathCommon.hpp
1 
17 #pragma once
18 #ifndef __H__OCULAR_ENGINE_MATH_COMMON__H__
19 #define __H__OCULAR_ENGINE_MATH_COMMON__H__
20 
21 #include "Definitions.hpp"
22 #include "Interpolation.hpp"
23 
24 #include <cmath>
25 #include <cstdint>
26 #include <algorithm>
27 
28 //------------------------------------------------------------------------------------------
29 
34 namespace Ocular
35 {
40  namespace Math
41  {
42  //----------------------------------------------------------------------------------
43  // Enums
44  //----------------------------------------------------------------------------------
45 
46  enum class IntersectionType : int8_t
47  {
48  Intersects = 0,
49  Outside = 1,
50  Inside = 2
51  };
52 
53  //----------------------------------------------------------------------------------
54  // Common Functions
55  //----------------------------------------------------------------------------------
56 
62  static int32_t Floor(const float value)
63  {
64  return (value > 0) ? static_cast<int>(value) : static_cast<int>(value) - 1;
65  }
66 
72  static int32_t Floor(const double value)
73  {
74  return (value > 0) ? static_cast<int>(value) : static_cast<int>(value) - 1;
75  }
76 
82  template<typename T>
83  static T InverseSqrt(T const& value)
84  {
85  return static_cast<T>(1) / sqrt(value);
86  }
87 
97  template<typename T>
98  static T Normalize(T const& value, T const& rangeStart, T const& rangeEnd)
99  {
100  // Yes this is a naive implementation. Have yet to find another that
101  // works on all types (integer, floating-point, positive, negative).
102 
103  T result = value;
104  T width = rangeEnd - rangeStart;
105 
106  while(result > rangeEnd)
107  {
108  result -= width;
109  }
110 
111  while(result < rangeStart)
112  {
113  result += width;
114  }
115 
116  return result;
117  }
118 
124  template<typename T>
125  static T RadiansToDegrees(T const& radians)
126  {
127  double dRads = static_cast<double>(radians);
128  dRads = Normalize<double>(dRads, -PI_TWO, PI_TWO);
129 
130  return static_cast<T>(dRads * PI_UNDER_180);
131  }
132 
138  template<typename T>
139  static T DegreesToRadians(T const& degrees)
140  {
141  double dDegs = static_cast<double>(degrees);
142  dDegs = Normalize<double>(dDegs, -360.0, 360.0);
143 
144  return static_cast<T>(dDegs * PI_OVER_180);
145  }
146 
154  template<typename T>
155  static T Clamp(T const value, T const lower = static_cast<T>(0), T const upper = static_cast<T>(1))
156  {
157  return ((value < lower) ? lower : (value > upper) ? upper : value);
158  }
159 
172  template<typename T>
173  static T RoundUpDecimal(T value, int const precision)
174  {
175  double result = static_cast<double>(value);
176 
177  result *= std::pow(10, precision);
178  result = std::ceil(result);
179  result /= std::pow(10, precision);
180 
181  return static_cast<T>(result);
182  }
183 
199  template<typename T>
200  static T RoundUpPowTen(T value, int const precision)
201  {
202  double result = static_cast<double>(value);
203 
204  result /= std::pow(10, precision);
205  result = std::ceil(result);
206  result *= std::pow(10, precision);
207 
208  return static_cast<T>(result);
209  }
210 
223  template<typename T>
224  static T RoundDownDecimal(T value, int const precision)
225  {
226  double result = static_cast<double>(value);
227 
228  result *= std::pow(10, precision);
229  result = std::floor(result);
230  result /= std::pow(10, precision);
231 
232  return static_cast<T>(result);
233  }
234 
250  template<typename T>
251  static T RoundDownPowTen(T value, int const precision)
252  {
253  double result = static_cast<double>(value);
254 
255  result /= std::pow(10, precision);
256  result = std::floor(value);
257  result *= std::pow(10, precision);
258 
259  return static_cast<T>(result);
260  }
261 
276  template<typename T>
277  static T RoundDecimal(T value, int const precision)
278  {
279  T result = value;
280 
281  const double up = RoundUpDecimal(value, precision);
282  const double down = RoundDownDecimal(value, precision);
283 
284  const double upDiff = std::abs(static_cast<double>(value) - static_cast<double>(up));
285  const double downDiff = std::abs(static_cast<double>(value) - static_cast<double>(down));
286 
287  if(upDiff < downDiff)
288  {
289  result = static_cast<T>(up);
290  }
291  else
292  {
293  result = static_cast<T>(down);
294  }
295 
296  return result;
297  }
298 
314  template<typename T>
315  static T RoundPowTen(T value, int const precision)
316  {
317  T up = RoundUpPowTen(value, precision);
318  T down = RoundDownPowTen(value, precision);
319 
320  T upDiff = static_cast<T>(std::abs(static_cast<double>(value)-static_cast<double>(up)));
321  T downDiff = static_cast<T>(std::abs(static_cast<double>(value)-static_cast<double>(down)));
322 
323  if(upDiff < downDiff)
324  {
325  return up;
326  }
327  else
328  {
329  return down;
330  }
331  }
332 
339  static inline uint32_t Clz(uint32_t const value)
340  {
341  // Yes, there are multiple intrinsic methods available (_lzcnt, _lzcnt_u32, __builtin_clz) but Ocular
342  // is not targetting a specific architecture, compiler, OS, etc. and there are no native C++ calls for this op.
343 
344  // Source: http://embeddedgurus.com/state-space/2014/09/fast-deterministic-and-portable-counting-leading-zeros/
345 
346  static uint8_t const table[] = {
347  32U, 31U, 30U, 30U, 29U, 29U, 29U, 29U,
348  28U, 28U, 28U, 28U, 28U, 28U, 28U, 28U,
349  27U, 27U, 27U, 27U, 27U, 27U, 27U, 27U,
350  27U, 27U, 27U, 27U, 27U, 27U, 27U, 27U,
351  26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
352  26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
353  26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
354  26U, 26U, 26U, 26U, 26U, 26U, 26U, 26U,
355  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
356  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
357  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
358  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
359  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
360  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
361  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
362  25U, 25U, 25U, 25U, 25U, 25U, 25U, 25U,
363  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
364  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
365  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
366  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
367  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
368  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
369  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
370  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
371  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
372  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
373  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
374  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
375  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
376  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
377  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U,
378  24U, 24U, 24U, 24U, 24U, 24U, 24U, 24U
379  };
380 
381  uint32_t n;
382 
383  if(value >= (1U << 16))
384  {
385  if(value >= (1U << 24))
386  {
387  n = 24U;
388  }
389  else
390  {
391  n = 16U;
392  }
393  }
394  else
395  {
396  if(value >= (1U << 8))
397  {
398  n = 8U;
399  }
400  else
401  {
402  n = 0U;
403  }
404  }
405 
406  return (uint32_t)(table[value >> n]) - n;
407  }
408 
415  static inline uint32_t Clz(uint64_t value)
416  {
417  // Yes, there are multiple intrinsic methods available (_lzcnt64, _lzcnt_u64, __builtin_clz) but Ocular
418  // is not targetting a specific architecture, compiler, OS, etc. and there are no native C++ calls for this op.
419 
420  // Naive implementation, yes. But all of the 'fancy' solutions seem to break down with 64-bit values.
421 
422  // Source: http://codingforspeed.com/counting-the-number-of-leading-zeros-for-a-32-bit-integer-signed-or-unsigned/
423 
424  uint32_t result = 0;
425 
426  if(value == 0)
427  {
428  result = 64;
429  }
430  else
431  {
432  while(value >>= 1)
433  {
434  result++;
435  }
436 
437  result = (64 - (result + 1));
438  }
439 
440  return result;
441  }
442  }
446 }
451 //------------------------------------------------------------------------------------------
452 
453 #endif
Note: Once this library is made dynamic, this will no longer be needed.
Definition: Common.hpp:70