numeric.h revision e4eec20f6263f4a42ae462456f60ea6c4518bb0a
1#ifndef ANDROID_DVR_NUMERIC_H_
2#define ANDROID_DVR_NUMERIC_H_
3
4#include <cmath>
5#include <limits>
6#include <random>
7#include <type_traits>
8
9#include <private/dvr/eigen.h>
10#include <private/dvr/types.h>
11
12namespace android {
13namespace dvr {
14
15template <typename FT>
16static inline FT ToDeg(FT f) {
17  return f * static_cast<FT>(180.0 / M_PI);
18}
19
20template <typename FT>
21static inline FT ToRad(FT f) {
22  return f * static_cast<FT>(M_PI / 180.0);
23}
24
25// Adjusts `x` to the periodic range `[lo, hi]` (to normalize angle values
26// for example).
27template <typename T>
28T NormalizePeriodicRange(T x, T lo, T hi) {
29  T range_size = hi - lo;
30
31  while (x < lo) {
32    x += range_size;
33  }
34
35  while (x > hi) {
36    x -= range_size;
37  }
38
39  return x;
40}
41
42// Normalizes a measurement in radians.
43// @param x the angle to be normalized
44// @param centre the point around which to normalize the range
45// @return the value of x, normalized to the range [centre - 180, centre + 180]
46template <typename T>
47T NormalizeDegrees(T x, T centre = static_cast<T>(180.0)) {
48  return NormalizePeriodicRange(x, centre - static_cast<T>(180.0),
49                                centre + static_cast<T>(180.0));
50}
51
52// Normalizes a measurement in radians.
53// @param x the angle to be normalized
54// @param centre the point around which to normalize the range
55// @return the value of x, normalized to the range
56//         [centre - M_PI, centre + M_PI]
57// @remark the centre parameter is to make it possible to specify a different
58//         periodic range. This is useful if you are planning on comparing two
59//         angles close to 0 or M_PI, so that one might not accidentally end
60//         up on the other side of the range
61template <typename T>
62T NormalizeRadians(T x, T centre = static_cast<T>(M_PI)) {
63  return NormalizePeriodicRange(x, centre - static_cast<T>(M_PI),
64                                centre + static_cast<T>(M_PI));
65}
66
67static inline vec2i Round(const vec2& v) {
68  return vec2i(roundf(v.x()), roundf(v.y()));
69}
70
71static inline vec2i Scale(const vec2i& v, float scale) {
72  return vec2i(roundf(static_cast<float>(v.x()) * scale),
73               roundf(static_cast<float>(v.y()) * scale));
74}
75
76// Re-maps `x` from `[lba,uba]` to `[lbb,ubb]`.
77template <typename T>
78T ConvertRange(T x, T lba, T uba, T lbb, T ubb) {
79  return (((x - lba) * (ubb - lbb)) / (uba - lba)) + lbb;
80}
81
82template <typename R1, typename R2>
83static inline vec2 MapPoint(const vec2& pt, const R1& from, const R2& to) {
84  vec2 normalized((pt - vec2(from.p1)).array() / vec2(from.GetSize()).array());
85  return (normalized * vec2(to.GetSize())) + vec2(to.p1);
86}
87
88template <typename T>
89inline bool IsZero(const T& v,
90                   const T& tol = std::numeric_limits<T>::epsilon()) {
91  return std::abs(v) <= tol;
92}
93
94template <typename T>
95inline bool IsEqual(const T& a, const T& b,
96                    const T& tol = std::numeric_limits<T>::epsilon()) {
97  return std::abs(b - a) <= tol;
98}
99
100template <typename T>
101T Square(const T& x) {
102  return x * x;
103}
104
105template <typename T>
106T RandomInRange(T lo, T hi,
107                typename
108                std::enable_if<std::is_floating_point<T>::value>::type* = 0) {
109  std::random_device rd;
110  std::mt19937 gen(rd());
111  std::uniform_real_distribution<T> distro(lo, hi);
112  return distro(gen);
113}
114
115template <typename T>
116T RandomInRange(T lo, T hi,
117                typename
118                std::enable_if<std::is_integral<T>::value>::type* = 0) {
119  std::random_device rd;
120  std::mt19937 gen(rd());
121  std::uniform_int_distribution<T> distro(lo, hi);
122  return distro(gen);
123}
124
125template <typename Derived1, typename Derived2>
126Derived1 RandomInRange(
127    const Eigen::MatrixBase<Derived1>& lo,
128    const Eigen::MatrixBase<Derived2>& hi) {
129  using Matrix1_t = Eigen::MatrixBase<Derived1>;
130  using Matrix2_t = Eigen::MatrixBase<Derived2>;
131
132  EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Matrix1_t, Matrix2_t);
133
134  Derived1 result = Matrix1_t::Zero();
135
136  for (int row = 0; row < result.rows(); ++row) {
137    for (int col = 0; col < result.cols(); ++col) {
138      result(row, col) = RandomInRange(lo(row, col), hi(row, col));
139    }
140  }
141
142  return result;
143}
144
145template <typename T>
146T RandomRange(T x) {
147  return RandomInRange(-x, x);
148}
149
150template <typename T>
151T Clamp(T x, T lo, T hi) {
152  return std::min(std::max(x, lo), hi);
153}
154
155inline mat3 ScaleMatrix(const vec2& scale_xy) {
156  return mat3(Eigen::Scaling(scale_xy[0], scale_xy[1], 1.0f));
157}
158
159inline mat3 TranslationMatrix(const vec2& translation) {
160  return mat3(Eigen::Translation2f(translation));
161}
162
163inline mat4 TranslationMatrix(const vec3& translation) {
164  return mat4(Eigen::Translation3f(translation));
165}
166
167inline vec2 TransformPoint(const mat3& m, const vec2& p) {
168  return m.linear() * p + m.translation();
169}
170
171inline vec2 TransformVector(const mat3& m, const vec2& p) {
172  return m.linear() * p;
173}
174
175}  // namespace dvr
176}  // namespace android
177
178#endif  // ANDROID_DVR_NUMERIC_H_
179