diff options
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/base/misc_math.h')
-rw-r--r-- | src/3rdparty/resonance-audio/resonance_audio/base/misc_math.h | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/base/misc_math.h b/src/3rdparty/resonance-audio/resonance_audio/base/misc_math.h new file mode 100644 index 000000000..5993eb55d --- /dev/null +++ b/src/3rdparty/resonance-audio/resonance_audio/base/misc_math.h @@ -0,0 +1,385 @@ +/* +Copyright 2018 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS-IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef RESONANCE_AUDIO_BASE_MISC_MATH_H_ +#define RESONANCE_AUDIO_BASE_MISC_MATH_H_ + +#ifndef _USE_MATH_DEFINES +#define _USE_MATH_DEFINES // Enable MSVC math constants (e.g., M_PI). +#endif // _USE_MATH_DEFINES + +#include <algorithm> +#include <cmath> +#include <cstdint> +#include <limits> +#include <utility> +#include <vector> + +#include "base/integral_types.h" +#include "Eigen/Dense" +#include "base/constants_and_types.h" +#include "base/logging.h" + +namespace vraudio { + +class WorldPosition : public Eigen::Matrix<float, 3, 1, Eigen::DontAlign> { + public: + // Inherits all constructors with 1-or-more arguments. Necessary because + // MSVC12 doesn't support inheriting constructors. + template <typename Arg1, typename... Args> + WorldPosition(const Arg1& arg1, Args&&... args) + : Matrix(arg1, std::forward<Args>(args)...) {} + + // Constructs a zero vector. + WorldPosition(); + + // Returns True if other |WorldPosition| differs by at least |kEpsilonFloat|. + bool operator!=(const WorldPosition& other) const { + return std::abs(this->x() - other.x()) > kEpsilonFloat || + std::abs(this->y() - other.y()) > kEpsilonFloat || + std::abs(this->z() - other.z()) > kEpsilonFloat; + } +}; + +class WorldRotation : public Eigen::Quaternion<float, Eigen::DontAlign> { + public: + // Inherits all constructors with 1-or-more arguments. Necessary because + // MSVC12 doesn't support inheriting constructors. + template <typename Arg1, typename... Args> + WorldRotation(const Arg1& arg1, Args&&... args) + : Quaternion(arg1, std::forward<Args>(args)...) {} + + // Constructs an identity rotation. + WorldRotation(); + + // Returns the shortest arc between two |WorldRotation|s in radians. + float AngularDifferenceRad(const WorldRotation& other) const { + const Quaternion difference = this->inverse() * other; + return static_cast<float>(Eigen::AngleAxisf(difference).angle()); + } +}; + +typedef Eigen::AngleAxis<float> AngleAxisf; + +typedef WorldPosition AudioPosition; + +typedef WorldRotation AudioRotation; + +// Converts |world_position| into an equivalent audio space position. +// The world space follows the typical CG coordinate system convention: +// Positive x points right, positive y points up, negative z points forward. +// The audio space follows the ambiX coordinate system convention that is +// commonly accepted in literature [http://goo.gl/XdYNm9]: +// Positive x points forward, negative y points right, positive z points up. +// Positions in both world space and audio space are in meters. +// +// @param world_position 3D position in world space. +// @param audio_position Output 3D position in audio space. +inline void ConvertAudioFromWorldPosition(const WorldPosition& world_position, + AudioPosition* audio_position) { + DCHECK(audio_position); + (*audio_position)(0) = -world_position[2]; + (*audio_position)(1) = -world_position[0]; + (*audio_position)(2) = world_position[1]; +} + +// Converts |audio_position| into an equivalent world space position. +// The world space follows the typical CG coordinate system convention: +// Positive x points right, positive y points up, negative z points forward. +// The audio space follows the ambiX coordinate system convention that is +// commonly accepted in literature [http://goo.gl/XdYNm9]: +// Positive x points forward, negative y points right, positive z points up. +// Positions in both world space and audio space are in meters. +// +// @param audio_position 3D position in audio space. +// @param world_position Output 3D position in world space. +inline void ConvertWorldFromAudioPosition(const AudioPosition& audio_position, + AudioPosition* world_position) { + DCHECK(world_position); + (*world_position)(0) = -audio_position[1]; + (*world_position)(1) = audio_position[2]; + (*world_position)(2) = -audio_position[0]; +} + +// Converts |world_rotation| into an equivalent audio space rotation. +// The world space follows the typical CG coordinate system convention: +// Positive x points right, positive y points up, negative z points forward. +// The audio space follows the ambiX coordinate system convention that is +// commonly accepted in literature [http://goo.gl/XdYNm9]: +// Positive x points forward, negative y points right, positive z points up. +// Positions in both world space and audio space are in meters. +// +// @param world_rotation 3D rotation in world space. +// @param audio_rotation Output 3D rotation in audio space. +inline void ConvertAudioFromWorldRotation(const WorldRotation& world_rotation, + AudioRotation* audio_rotation) { + DCHECK(audio_rotation); + audio_rotation->w() = world_rotation.w(); + audio_rotation->x() = -world_rotation.x(); + audio_rotation->y() = world_rotation.y(); + audio_rotation->z() = -world_rotation.z(); +} + +// Returns the relative direction vector |from_position| and |to_position| by +// rotating the relative position vector with respect to |from_rotation|. +// +// @param from_position Origin position of the direction. +// @param from_rotation Origin orientation of the direction. +// @param to_position Target position of the direction. +// @param relative_direction Relative direction vector (not normalized). +inline void GetRelativeDirection(const WorldPosition& from_position, + const WorldRotation& from_rotation, + const WorldPosition& to_position, + WorldPosition* relative_direction) { + DCHECK(relative_direction); + *relative_direction = + from_rotation.conjugate() * (to_position - from_position); +} + +// Returns the closest relative position in an axis-aligned bounding box to the +// given |relative_position|. +// +// @param position Input position relative to the center of the bounding box. +// @param aabb_dimensions Bounding box dimensions. +// @return aabb bounded position. +inline void GetClosestPositionInAabb(const WorldPosition& relative_position, + const WorldPosition& aabb_dimensions, + WorldPosition* closest_position) { + DCHECK(closest_position); + const WorldPosition aabb_offset = 0.5f * aabb_dimensions; + (*closest_position)[0] = + std::min(std::max(relative_position[0], -aabb_offset[0]), aabb_offset[0]); + (*closest_position)[1] = + std::min(std::max(relative_position[1], -aabb_offset[1]), aabb_offset[1]); + (*closest_position)[2] = + std::min(std::max(relative_position[2], -aabb_offset[2]), aabb_offset[2]); +} + +// Returns true if given world |position| is in given axis-aligned bounding box. +// +// @param position Position to be tested. +// @param aabb_center Bounding box center. +// @param aabb_dimensions Bounding box dimensions. +// @return True if |position| is within bounding box, false otherwise. +inline bool IsPositionInAabb(const WorldPosition& position, + const WorldPosition& aabb_center, + const WorldPosition& aabb_dimensions) { + return std::abs(position[0] - aabb_center[0]) <= 0.5f * aabb_dimensions[0] && + std::abs(position[1] - aabb_center[1]) <= 0.5f * aabb_dimensions[1] && + std::abs(position[2] - aabb_center[2]) <= 0.5f * aabb_dimensions[2]; +} + +// Returns true if an integer overflow occurred during the calculation of +// x = a * b. +// +// @param a First multiplicand. +// @param b Second multiplicand. +// @param x Product. +// @return True if integer overflow occurred, false otherwise. +template <typename T> +inline bool DoesIntegerMultiplicationOverflow(T a, T b, T x) { + // Detects an integer overflow occurs by inverting the multiplication and + // testing for x / a != b. + return a == 0 ? false : (x / a != b); +} + +// Returns true if an integer overflow occurred during the calculation of +// a + b. +// +// @param a First summand. +// @param b Second summand. +// @return True if integer overflow occurred, false otherwise. +template <typename T> +inline bool DoesIntegerAdditionOverflow(T a, T b) { + T x = a + b; + return x < b; +} + +// Safely converts an int to a size_t. +// +// @param i Integer input. +// @param x Size_t output. +// @return True if integer overflow occurred, false otherwise. +inline bool DoesIntSafelyConvertToSizeT(int i, size_t* x) { + if (i < 0) { + return false; + } + *x = static_cast<size_t>(i); + return true; +} + +// Safely converts a size_t to an int. +// +// @param i Size_t input. +// @param x Integer output. +// @return True if integer overflow occurred, false otherwise. +inline bool DoesSizeTSafelyConvertToInt(size_t i, int* x) { + if (i > static_cast<size_t>(std::numeric_limits<int>::max())) { + return false; + } + *x = static_cast<int>(i); + return true; +} + +// Finds the greatest common divisor between two integer values using the +// Euclidean algorithm. Always returns a positive integer. +// +// @param a First of the two integer values. +// @param b second of the two integer values. +// @return The greatest common divisor of the two integer values. +inline int FindGcd(int a, int b) { + a = std::abs(a); + b = std::abs(b); + int temp_value = 0; + while (b != 0) { + temp_value = b; + b = a % b; + a = temp_value; + } + return a; +} + +// Finds the next power of two from an integer. This method works with values +// representable by unsigned 32 bit integers. +// +// @param input Integer value. +// @return The next power of two from |input|. +inline size_t NextPowTwo(size_t input) { + // Ensure the value fits in a uint32_t. + DCHECK_LT(static_cast<uint64_t>(input), + static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())); + uint32_t number = static_cast<uint32_t>(--input); + number |= number >> 1; // Take care of 2 bit numbers. + number |= number >> 2; // Take care of 4 bit numbers. + number |= number >> 4; // Take care of 8 bit numbers. + number |= number >> 8; // Take care of 16 bit numbers. + number |= number >> 16; // Take care of 32 bit numbers. + number++; + return static_cast<size_t>(number); +} + +// Returns the factorial (!) of x. If x < 0, it returns 0. +inline float Factorial(int x) { + if (x < 0) return 0.0f; + float result = 1.0f; + for (; x > 0; --x) result *= static_cast<float>(x); + return result; +} + +// Returns the double factorial (!!) of x. +// For odd x: 1 * 3 * 5 * ... * (x - 2) * x +// For even x: 2 * 4 * 6 * ... * (x - 2) * x +// If x < 0, it returns 0. +inline float DoubleFactorial(int x) { + if (x < 0) return 0.0f; + float result = 1.0f; + for (; x > 0; x -= 2) result *= static_cast<float>(x); + return result; +} + +// This is a *safe* alternative to std::equal function as a workaround in order +// to avoid MSVC compiler warning C4996 for unchecked iterators (see +// https://msdn.microsoft.com/en-us/library/aa985965.aspx). +// Also note that, an STL equivalent of this function was introduced in C++14 to +// be replaced with this implementation (see version (5) in +// http://en.cppreference.com/w/cpp/algorithm/equal). +template <typename Iterator> +inline bool EqualSafe(const Iterator& lhs_begin, const Iterator& lhs_end, + const Iterator& rhs_begin, const Iterator& rhs_end) { + auto lhs_itr = lhs_begin; + auto rhs_itr = rhs_begin; + while (lhs_itr != lhs_end && rhs_itr != rhs_end) { + if (*lhs_itr != *rhs_itr) { + return false; + } + ++lhs_itr; + ++rhs_itr; + } + return lhs_itr == lhs_end && rhs_itr == rhs_end; +} + +// Fast reciprocal of square-root. See: https://goo.gl/fqvstz for details. +// +// @param input The number to be inverse rooted. +// @return An approximation of the reciprocal square root of |input|. +inline float FastReciprocalSqrt(float input) { + const float kThreeHalfs = 1.5f; + const uint32_t kMagicNumber = 0x5f3759df; + + // Approximate a logarithm by aliasing to an integer. + uint32_t integer; + memcpy(&integer, &input, sizeof(float)); + integer = kMagicNumber - (integer >> 1); + float approximation; + memcpy(&approximation, &integer, sizeof(float)); + const float half_input = input * 0.5f; + // One iteration of Newton's method. + return approximation * + (kThreeHalfs - (half_input * approximation * approximation)); +} + +// Finds the best-fitting line to a given set of 2D points by minimizing the +// sum of the squares of the vertical (along y-axis) offsets. The slope and +// intercept of the fitted line are recorded, as well as the coefficient of +// determination, which gives the quality of the fitting. +// See http://mathworld.wolfram.com/LeastSquaresFitting.html for how to compute +// these values. +// +// @param x_array Array of the x coordinates of the points. +// @param y_array Array of the y coordinates of the points. +// @param slope Output slope of the fitted line. +// @param intercept Output slope of the fitted line. +// @param r_squared Coefficient of determination. +// @return False if the fitting fails. +bool LinearLeastSquareFitting(const std::vector<float>& x_array, + const std::vector<float>& y_array, float* slope, + float* intercept, float* r_squared); + +// Computes |base|^|exp|, where |exp| is a *non-negative* integer, with the +// squared exponentiation (a.k.a double-and-add) method. +// When T is a floating point type, this has the same semantics as pow(), but +// is much faster. +// T can also be any integral type, in which case computations will be +// performed in the value domain of this integral type, and overflow semantics +// will be those of T. +// You can also use any type for which operator*= is defined. +// See : + +// This method is reproduced here so vraudio classes don't need to depend on +// //util/math/mathutil.h +// +// @tparam base Input to the exponent function. Any type for which *= is +// defined. +// @param exp Integer exponent, must be greater than or equal to zero. +// @return |base|^|exp|. +template <typename T> +static inline T IntegerPow(T base, int exp) { + DCHECK_GE(exp, 0); + T result = static_cast<T>(1); + while (true) { + if (exp & 1) { + result *= base; + } + exp >>= 1; + if (!exp) break; + base *= base; + } + return result; +} + +} // namespace vraudio + +#endif // RESONANCE_AUDIO_BASE_MISC_MATH_H_ |