RavEngine
Loading...
Searching...
No Matches
misc_math.h
1/*
2Copyright 2018 Google Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS-IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef RESONANCE_AUDIO_BASE_MISC_MATH_H_
18#define RESONANCE_AUDIO_BASE_MISC_MATH_H_
19
20#ifndef _USE_MATH_DEFINES
21#define _USE_MATH_DEFINES // Enable MSVC math constants (e.g., M_PI).
22#endif // _USE_MATH_DEFINES
23
24#include <algorithm>
25#include <cmath>
26#include <cstdint>
27#include <limits>
28#include <utility>
29#include <vector>
30
31#include "base/integral_types.h"
32#include "Eigen/Dense"
33#include "base/constants_and_types.h"
34#include "base/logging.h"
35
36namespace vraudio {
37
38class WorldPosition : public Eigen::Matrix<float, 3, 1, Eigen::DontAlign> {
39 public:
40 // Inherits all constructors with 1-or-more arguments. Necessary because
41 // MSVC12 doesn't support inheriting constructors.
42 template <typename Arg1, typename... Args>
43 WorldPosition(const Arg1& arg1, Args&&... args)
44 : Matrix(arg1, std::forward<Args>(args)...) {}
45
46 // Constructs a zero vector.
48
49 // Returns True if other |WorldPosition| differs by at least |kEpsilonFloat|.
50 bool operator!=(const WorldPosition& other) const {
51 return std::abs(this->x() - other.x()) > kEpsilonFloat ||
52 std::abs(this->y() - other.y()) > kEpsilonFloat ||
53 std::abs(this->z() - other.z()) > kEpsilonFloat;
54 }
55};
56
57class WorldRotation : public Eigen::Quaternion<float, Eigen::DontAlign> {
58 public:
59 // Inherits all constructors with 1-or-more arguments. Necessary because
60 // MSVC12 doesn't support inheriting constructors.
61 template <typename Arg1, typename... Args>
62 WorldRotation(const Arg1& arg1, Args&&... args)
63 : Quaternion(arg1, std::forward<Args>(args)...) {}
64
65 // Constructs an identity rotation.
67
68 // Returns the shortest arc between two |WorldRotation|s in radians.
69 float AngularDifferenceRad(const WorldRotation& other) const {
70 const Quaternion difference = this->inverse() * other;
71 return static_cast<float>(Eigen::AngleAxisf(difference).angle());
72 }
73};
74
76
78
80
81// Converts |world_position| into an equivalent audio space position.
82// The world space follows the typical CG coordinate system convention:
83// Positive x points right, positive y points up, negative z points forward.
84// The audio space follows the ambiX coordinate system convention that is
85// commonly accepted in literature [http://goo.gl/XdYNm9]:
86// Positive x points forward, negative y points right, positive z points up.
87// Positions in both world space and audio space are in meters.
88//
89// @param world_position 3D position in world space.
90// @param audio_position Output 3D position in audio space.
91inline void ConvertAudioFromWorldPosition(const WorldPosition& world_position,
92 AudioPosition* audio_position) {
93 DCHECK(audio_position);
94 (*audio_position)(0) = -world_position[2];
95 (*audio_position)(1) = -world_position[0];
96 (*audio_position)(2) = world_position[1];
97}
98
99// Converts |audio_position| into an equivalent world space position.
100// The world space follows the typical CG coordinate system convention:
101// Positive x points right, positive y points up, negative z points forward.
102// The audio space follows the ambiX coordinate system convention that is
103// commonly accepted in literature [http://goo.gl/XdYNm9]:
104// Positive x points forward, negative y points right, positive z points up.
105// Positions in both world space and audio space are in meters.
106//
107// @param audio_position 3D position in audio space.
108// @param world_position Output 3D position in world space.
109inline void ConvertWorldFromAudioPosition(const AudioPosition& audio_position,
110 AudioPosition* world_position) {
111 DCHECK(world_position);
112 (*world_position)(0) = -audio_position[1];
113 (*world_position)(1) = audio_position[2];
114 (*world_position)(2) = -audio_position[0];
115}
116
117// Converts |world_rotation| into an equivalent audio space rotation.
118// The world space follows the typical CG coordinate system convention:
119// Positive x points right, positive y points up, negative z points forward.
120// The audio space follows the ambiX coordinate system convention that is
121// commonly accepted in literature [http://goo.gl/XdYNm9]:
122// Positive x points forward, negative y points right, positive z points up.
123// Positions in both world space and audio space are in meters.
124//
125// @param world_rotation 3D rotation in world space.
126// @param audio_rotation Output 3D rotation in audio space.
127inline void ConvertAudioFromWorldRotation(const WorldRotation& world_rotation,
128 AudioRotation* audio_rotation) {
129 DCHECK(audio_rotation);
130 audio_rotation->w() = world_rotation.w();
131 audio_rotation->x() = -world_rotation.x();
132 audio_rotation->y() = world_rotation.y();
133 audio_rotation->z() = -world_rotation.z();
134}
135
136// Returns the relative direction vector |from_position| and |to_position| by
137// rotating the relative position vector with respect to |from_rotation|.
138//
139// @param from_position Origin position of the direction.
140// @param from_rotation Origin orientation of the direction.
141// @param to_position Target position of the direction.
142// @param relative_direction Relative direction vector (not normalized).
143inline void GetRelativeDirection(const WorldPosition& from_position,
144 const WorldRotation& from_rotation,
145 const WorldPosition& to_position,
146 WorldPosition* relative_direction) {
147 DCHECK(relative_direction);
148 *relative_direction =
149 from_rotation.conjugate() * (to_position - from_position);
150}
151
152// Returns the closest relative position in an axis-aligned bounding box to the
153// given |relative_position|.
154//
155// @param position Input position relative to the center of the bounding box.
156// @param aabb_dimensions Bounding box dimensions.
157// @return aabb bounded position.
158inline void GetClosestPositionInAabb(const WorldPosition& relative_position,
159 const WorldPosition& aabb_dimensions,
160 WorldPosition* closest_position) {
161 DCHECK(closest_position);
162 const WorldPosition aabb_offset = 0.5f * aabb_dimensions;
163 (*closest_position)[0] =
164 std::min(std::max(relative_position[0], -aabb_offset[0]), aabb_offset[0]);
165 (*closest_position)[1] =
166 std::min(std::max(relative_position[1], -aabb_offset[1]), aabb_offset[1]);
167 (*closest_position)[2] =
168 std::min(std::max(relative_position[2], -aabb_offset[2]), aabb_offset[2]);
169}
170
171// Returns true if given world |position| is in given axis-aligned bounding box.
172//
173// @param position Position to be tested.
174// @param aabb_center Bounding box center.
175// @param aabb_dimensions Bounding box dimensions.
176// @return True if |position| is within bounding box, false otherwise.
177inline bool IsPositionInAabb(const WorldPosition& position,
178 const WorldPosition& aabb_center,
179 const WorldPosition& aabb_dimensions) {
180 return std::abs(position[0] - aabb_center[0]) <= 0.5f * aabb_dimensions[0] &&
181 std::abs(position[1] - aabb_center[1]) <= 0.5f * aabb_dimensions[1] &&
182 std::abs(position[2] - aabb_center[2]) <= 0.5f * aabb_dimensions[2];
183}
184
185// Returns true if an integer overflow occurred during the calculation of
186// x = a * b.
187//
188// @param a First multiplicand.
189// @param b Second multiplicand.
190// @param x Product.
191// @return True if integer overflow occurred, false otherwise.
192template <typename T>
193inline bool DoesIntegerMultiplicationOverflow(T a, T b, T x) {
194 // Detects an integer overflow occurs by inverting the multiplication and
195 // testing for x / a != b.
196 return a == 0 ? false : (x / a != b);
197}
198
199// Returns true if an integer overflow occurred during the calculation of
200// a + b.
201//
202// @param a First summand.
203// @param b Second summand.
204// @return True if integer overflow occurred, false otherwise.
205template <typename T>
206inline bool DoesIntegerAdditionOverflow(T a, T b) {
207 T x = a + b;
208 return x < b;
209}
210
211// Safely converts an int to a size_t.
212//
213// @param i Integer input.
214// @param x Size_t output.
215// @return True if integer overflow occurred, false otherwise.
216inline bool DoesIntSafelyConvertToSizeT(int i, size_t* x) {
217 if (i < 0) {
218 return false;
219 }
220 *x = static_cast<size_t>(i);
221 return true;
222}
223
224// Safely converts a size_t to an int.
225//
226// @param i Size_t input.
227// @param x Integer output.
228// @return True if integer overflow occurred, false otherwise.
229inline bool DoesSizeTSafelyConvertToInt(size_t i, int* x) {
230 if (i > static_cast<size_t>(std::numeric_limits<int>::max())) {
231 return false;
232 }
233 *x = static_cast<int>(i);
234 return true;
235}
236
237// Finds the greatest common divisor between two integer values using the
238// Euclidean algorithm. Always returns a positive integer.
239//
240// @param a First of the two integer values.
241// @param b second of the two integer values.
242// @return The greatest common divisor of the two integer values.
243inline int FindGcd(int a, int b) {
244 a = std::abs(a);
245 b = std::abs(b);
246 int temp_value = 0;
247 while (b != 0) {
248 temp_value = b;
249 b = a % b;
250 a = temp_value;
251 }
252 return a;
253}
254
255// Finds the next power of two from an integer. This method works with values
256// representable by unsigned 32 bit integers.
257//
258// @param input Integer value.
259// @return The next power of two from |input|.
260inline size_t NextPowTwo(size_t input) {
261 // Ensure the value fits in a uint32_t.
262 DCHECK_LT(static_cast<uint64_t>(input),
263 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
264 uint32_t number = static_cast<uint32_t>(--input);
265 number |= number >> 1; // Take care of 2 bit numbers.
266 number |= number >> 2; // Take care of 4 bit numbers.
267 number |= number >> 4; // Take care of 8 bit numbers.
268 number |= number >> 8; // Take care of 16 bit numbers.
269 number |= number >> 16; // Take care of 32 bit numbers.
270 number++;
271 return static_cast<size_t>(number);
272}
273
274// Returns the factorial (!) of x. If x < 0, it returns 0.
275inline float Factorial(int x) {
276 if (x < 0) return 0.0f;
277 float result = 1.0f;
278 for (; x > 0; --x) result *= static_cast<float>(x);
279 return result;
280}
281
282// Returns the double factorial (!!) of x.
283// For odd x: 1 * 3 * 5 * ... * (x - 2) * x
284// For even x: 2 * 4 * 6 * ... * (x - 2) * x
285// If x < 0, it returns 0.
286inline float DoubleFactorial(int x) {
287 if (x < 0) return 0.0f;
288 float result = 1.0f;
289 for (; x > 0; x -= 2) result *= static_cast<float>(x);
290 return result;
291}
292
293// This is a *safe* alternative to std::equal function as a workaround in order
294// to avoid MSVC compiler warning C4996 for unchecked iterators (see
295// https://msdn.microsoft.com/en-us/library/aa985965.aspx).
296// Also note that, an STL equivalent of this function was introduced in C++14 to
297// be replaced with this implementation (see version (5) in
298// http://en.cppreference.com/w/cpp/algorithm/equal).
299template <typename Iterator>
300inline bool EqualSafe(const Iterator& lhs_begin, const Iterator& lhs_end,
301 const Iterator& rhs_begin, const Iterator& rhs_end) {
302 auto lhs_itr = lhs_begin;
303 auto rhs_itr = rhs_begin;
304 while (lhs_itr != lhs_end && rhs_itr != rhs_end) {
305 if (*lhs_itr != *rhs_itr) {
306 return false;
307 }
308 ++lhs_itr;
309 ++rhs_itr;
310 }
311 return lhs_itr == lhs_end && rhs_itr == rhs_end;
312}
313
314// Fast reciprocal of square-root. See: https://goo.gl/fqvstz for details.
315//
316// @param input The number to be inverse rooted.
317// @return An approximation of the reciprocal square root of |input|.
318inline float FastReciprocalSqrt(float input) {
319 const float kThreeHalfs = 1.5f;
320 const uint32_t kMagicNumber = 0x5f3759df;
321
322 // Approximate a logarithm by aliasing to an integer.
323 uint32_t integer = *reinterpret_cast<uint32_t*>(&input);
324 integer = kMagicNumber - (integer >> 1);
325 float approximation = *reinterpret_cast<float*>(&integer);
326 const float half_input = input * 0.5f;
327 // One iteration of Newton's method.
328 return approximation *
329 (kThreeHalfs - (half_input * approximation * approximation));
330}
331
332// Finds the best-fitting line to a given set of 2D points by minimizing the
333// sum of the squares of the vertical (along y-axis) offsets. The slope and
334// intercept of the fitted line are recorded, as well as the coefficient of
335// determination, which gives the quality of the fitting.
336// See http://mathworld.wolfram.com/LeastSquaresFitting.html for how to compute
337// these values.
338//
339// @param x_array Array of the x coordinates of the points.
340// @param y_array Array of the y coordinates of the points.
341// @param slope Output slope of the fitted line.
342// @param intercept Output slope of the fitted line.
343// @param r_squared Coefficient of determination.
344// @return False if the fitting fails.
345bool LinearLeastSquareFitting(const std::vector<float>& x_array,
346 const std::vector<float>& y_array, float* slope,
347 float* intercept, float* r_squared);
348
349// Computes |base|^|exp|, where |exp| is a *non-negative* integer, with the
350// squared exponentiation (a.k.a double-and-add) method.
351// When T is a floating point type, this has the same semantics as pow(), but
352// is much faster.
353// T can also be any integral type, in which case computations will be
354// performed in the value domain of this integral type, and overflow semantics
355// will be those of T.
356// You can also use any type for which operator*= is defined.
357// See :
358
359// This method is reproduced here so vraudio classes don't need to depend on
360// //util/math/mathutil.h
361//
362// @tparam base Input to the exponent function. Any type for which *= is
363// defined.
364// @param exp Integer exponent, must be greater than or equal to zero.
365// @return |base|^|exp|.
366template <typename T>
367static inline T IntegerPow(T base, int exp) {
368 DCHECK_GE(exp, 0);
369 T result = static_cast<T>(1);
370 while (true) {
371 if (exp & 1) {
372 result *= base;
373 }
374 exp >>= 1;
375 if (!exp) break;
376 base *= base;
377 }
378 return result;
379}
380
381} // namespace vraudio
382
383#endif // RESONANCE_AUDIO_BASE_MISC_MATH_H_
Represents a 3D rotation as a rotation angle around an arbitrary 3D axis.
Definition AngleAxis.h:50
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:180
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix()
Default constructor.
Definition Matrix.h:259
EIGEN_DEVICE_FUNC Quaternion< Scalar > inverse() const
Definition Quaternion.h:720
The quaternion class used to represent 3D orientations and rotations.
Definition Quaternion.h:274
EIGEN_DEVICE_FUNC Quaternion()
Definition Quaternion.h:288
Definition misc_math.h:38
Definition misc_math.h:57
AngleAxis< float > AngleAxisf
Definition AngleAxis.h:157
GLM_FUNC_QUALIFIER vec< L, T, Q > exp(vec< L, T, Q > const &x)
Definition func_exponential.inl:80
uint64 uint64_t
Definition fwd.hpp:145
uint32 uint32_t
Definition fwd.hpp:131