MathUtils-Impl.hpp
Go to the documentation of this file.
1 // This code is based on Jet framework.
2 // Copyright (c) 2018 Doyub Kim
3 // CubbyFlow is voxel-based fluid simulation engine for computer games.
4 // Copyright (c) 2020 CubbyFlow Team
5 // Core Part: Chris Ohk, Junwoo Hwang, Jihong Sin, Seungwoo Yoo
6 // AI Part: Dongheon Cho, Minseo Kim
7 // We are making my contributions/submissions to this project solely in our
8 // personal capacity and are not conveying any rights to any intellectual
9 // property of any third parties.
10 
11 #ifndef CUBBYFLOW_MATH_UTILS_IMPL_HPP
12 #define CUBBYFLOW_MATH_UTILS_IMPL_HPP
13 
14 #include <Core/Utils/Constants.hpp>
15 
16 #include <algorithm>
17 #include <cassert>
18 #include <cmath>
19 
20 namespace CubbyFlow
21 {
22 template <typename T>
23 std::enable_if_t<std::is_arithmetic<T>::value, bool> Similar(T x, T y, T eps)
24 {
25  return std::abs(x - y) <= eps;
26 }
27 
28 template <typename T>
29 std::enable_if_t<std::is_arithmetic<T>::value, T> Sign(T x)
30 {
31  if (x >= 0)
32  {
33  return 1;
34  }
35 
36  return -1;
37 }
38 
39 template <typename T>
40 std::enable_if_t<std::is_arithmetic<T>::value, T> Min3(T x, T y, T z)
41 {
42  return std::min(std::min(x, y), z);
43 }
44 
45 template <typename T>
46 std::enable_if_t<std::is_arithmetic<T>::value, T> Max3(T x, T y, T z)
47 {
48  return std::max(std::max(x, y), z);
49 }
50 
51 template <typename T>
52 std::enable_if_t<std::is_arithmetic<T>::value, T> MinN(const T* x, size_t n)
53 {
54  T m = x[0];
55 
56  for (size_t i = 1; i < n; i++)
57  {
58  m = std::min(m, x[i]);
59  }
60 
61  return m;
62 }
63 
64 template <typename T>
65 std::enable_if_t<std::is_arithmetic<T>::value, T> MaxN(const T* x, size_t n)
66 {
67  T m = x[0];
68 
69  for (size_t i = 1; i < n; i++)
70  {
71  m = std::max(m, x[i]);
72  }
73 
74  return m;
75 }
76 
77 template <typename T>
78 std::enable_if_t<std::is_arithmetic<T>::value, T> AbsMin(T x, T y)
79 {
80  return (x * x < y * y) ? x : y;
81 }
82 
83 template <typename T>
84 std::enable_if_t<std::is_arithmetic<T>::value, T> AbsMax(T x, T y)
85 {
86  return (x * x > y * y) ? x : y;
87 }
88 
89 template <typename T>
90 std::enable_if_t<std::is_arithmetic<T>::value, T> AbsMinN(const T* x, size_t n)
91 {
92  T m = x[0];
93 
94  for (size_t i = 1; i < n; i++)
95  {
96  m = AbsMin(m, x[i]);
97  }
98 
99  return m;
100 }
101 
102 template <typename T>
103 std::enable_if_t<std::is_arithmetic<T>::value, T> AbsMaxN(const T* x, size_t n)
104 {
105  T m = x[0];
106 
107  for (size_t i = 1; i < n; i++)
108  {
109  m = AbsMax(m, x[i]);
110  }
111 
112  return m;
113 }
114 
115 template <typename T>
116 std::enable_if_t<std::is_arithmetic<T>::value, size_t> ArgMin2(T x, T y)
117 {
118  return (x < y) ? 0 : 1;
119 }
120 
121 template <typename T>
122 std::enable_if_t<std::is_arithmetic<T>::value, size_t> ArgMax2(T x, T y)
123 {
124  return (x > y) ? 0 : 1;
125 }
126 
127 template <typename T>
128 std::enable_if_t<std::is_arithmetic<T>::value, size_t> ArgMin3(T x, T y, T z)
129 {
130  if (x < y)
131  {
132  return (x < z) ? 0 : 2;
133  }
134  else
135  {
136  return (y < z) ? 1 : 2;
137  }
138 }
139 
140 template <typename T>
141 std::enable_if_t<std::is_arithmetic<T>::value, size_t> ArgMax3(T x, T y, T z)
142 {
143  if (x > y)
144  {
145  return (x > z) ? 0 : 2;
146  }
147  else
148  {
149  return (y > z) ? 1 : 2;
150  }
151 }
152 
153 template <typename T>
154 std::enable_if_t<std::is_arithmetic<T>::value, T> Square(T x)
155 {
156  return x * x;
157 }
158 
159 template <typename T>
160 std::enable_if_t<std::is_arithmetic<T>::value, T> Cubic(T x)
161 {
162  return x * x * x;
163 }
164 
165 template <typename T>
166 std::enable_if_t<std::is_arithmetic<T>::value, T> Clamp(T val, T low, T high)
167 {
168  if (val < low)
169  {
170  return low;
171  }
172 
173  if (val > high)
174  {
175  return high;
176  }
177 
178  return val;
179 }
180 
181 template <typename T>
182 std::enable_if_t<std::is_arithmetic<T>::value, T> DegreesToRadians(
183  T angleInDegrees)
184 {
185  return angleInDegrees * PI<T>() / 180;
186 }
187 
188 template <typename T>
189 std::enable_if_t<std::is_arithmetic<T>::value, T> RadiansToDegrees(
190  T angleInRadians)
191 {
192  return angleInRadians * 180 / PI<T>();
193 }
194 
195 template <typename T>
196 std::enable_if_t<std::is_arithmetic<T>::value> GetBarycentric(T x, size_t begin,
197  size_t end,
198  size_t& i, T& t)
199 {
200  assert(end > begin);
201 
202  T s = std::floor(x);
203  i = static_cast<size_t>(s);
204  const size_t size = end - begin;
205 
206  if (size == 1)
207  {
208  i = begin;
209  t = 0;
210  }
211  else if (i > end - 2)
212  {
213  i = end - 2;
214  t = 1;
215  }
216  else
217  {
218  t = static_cast<T>(x - s);
219  }
220 }
221 
222 template <typename T>
223 std::enable_if_t<std::is_arithmetic<T>::value> GetBarycentric(T x, size_t end,
224  size_t& i, T& t)
225 {
226  assert(end > 0);
227 
228  T s = std::floor(x);
229  i = static_cast<size_t>(s);
230  t = x - s;
231 
232  if (end == 1)
233  {
234  i = 0;
235  t = 0;
236  }
237  else if (i > end - 2)
238  {
239  i = end - 2;
240  t = 1;
241  }
242 }
243 
244 template <typename T>
245 std::enable_if_t<std::is_arithmetic<T>::value> GetBarycentric(T x,
246  ssize_t begin,
247  ssize_t end,
248  ssize_t& i, T& t)
249 {
250  assert(end > begin);
251 
252  T s = std::floor(x);
253  i = static_cast<ssize_t>(s);
254  const ssize_t size = end - begin;
255 
256  if (size == 1 || i < 0)
257  {
258  i = begin;
259  t = 0;
260  }
261  else if (i > end - 2)
262  {
263  i = end - 2;
264  t = 1;
265  }
266  else
267  {
268  t = static_cast<T>(x - s);
269  }
270 }
271 
272 template <typename T>
273 std::enable_if_t<std::is_arithmetic<T>::value> GetBarycentric(T x, ssize_t end,
274  ssize_t& i, T& t)
275 {
276  assert(end > 0);
277 
278  T s = std::floor(x);
279  i = static_cast<ssize_t>(s);
280  t = x - s;
281 
282  if (end == 1 || i < 0)
283  {
284  i = 0;
285  t = 0;
286  }
287  else if (i > end - 2)
288  {
289  i = end - 2;
290  t = 1;
291  }
292 }
293 
294 template <typename S, typename T>
295 std::enable_if_t<std::is_arithmetic<T>::value, S> Lerp(const S& f0, const S& f1,
296  T t)
297 {
298  return (1 - t) * f0 + t * f1;
299 }
300 
301 template <typename S, typename T>
302 std::enable_if_t<std::is_arithmetic<T>::value, S> BiLerp(
303  const S& f00, const S& f10, const S& f01, const S& f11, T tx, T ty)
304 {
305  return Lerp(Lerp(f00, f10, tx), Lerp(f01, f11, tx), ty);
306 }
307 
308 template <typename S, typename T>
309 std::enable_if_t<std::is_arithmetic<T>::value, S> TriLerp(
310  const S& f000, const S& f100, const S& f010, const S& f110, const S& f001,
311  const S& f101, const S& f011, const S& f111, T tx, T ty, T tz)
312 {
313  return Lerp(BiLerp(f000, f100, f010, f110, tx, ty),
314  BiLerp(f001, f101, f011, f111, tx, ty), tz);
315 }
316 
317 template <typename S, typename T>
318 std::enable_if_t<std::is_arithmetic<T>::value, S> CatmullRom(const S& f0,
319  const S& f1,
320  const S& f2,
321  const S& f3, T t)
322 {
323  S d1 = (f2 - f0) / 2;
324  S d2 = (f3 - f1) / 2;
325  S D1 = f2 - f1;
326 
327  S a3 = d1 + d2 - 2 * D1;
328  S a2 = 3 * D1 - 2 * d1 - d2;
329  S a1 = d1;
330  S a0 = f1;
331 
332  return a3 * Cubic(t) + a2 * Square(t) + a1 * t + a0;
333 }
334 
335 template <typename T>
336 std::enable_if_t<std::is_arithmetic<T>::value, T> MonotonicCatmullRom(
337  const T& f0, const T& f1, const T& f2, const T& f3, T t)
338 {
339  T d1 = (f2 - f0) / 2;
340  T d2 = (f3 - f1) / 2;
341  T D1 = f2 - f1;
342 
343  if (std::fabs(D1) < std::numeric_limits<double>::epsilon())
344  {
345  d1 = d2 = 0;
346  }
347 
348  if (Sign(D1) != Sign(d1))
349  {
350  d1 = 0;
351  }
352 
353  if (Sign(D1) != Sign(d2))
354  {
355  d2 = 0;
356  }
357 
358  T a3 = d1 + d2 - 2 * D1;
359  T a2 = 3 * D1 - 2 * d1 - d2;
360  T a1 = d1;
361  T a0 = f1;
362 
363  return a3 * Cubic(t) + a2 * Square(t) + a1 * t + a0;
364 }
365 } // namespace CubbyFlow
366 
367 #endif
std::enable_if_t< std::is_arithmetic< T >::value, size_t > ArgMax2(T x, T y)
Definition: MathUtils-Impl.hpp:122
std::enable_if_t< std::is_arithmetic< T >::value, size_t > ArgMax3(T x, T y, T z)
Definition: MathUtils-Impl.hpp:141
std::enable_if_t< std::is_arithmetic< T >::value, S > Lerp(const S &f0, const S &f1, T t)
Computes linear interpolation.
Definition: MathUtils-Impl.hpp:295
std::enable_if_t< std::is_arithmetic< T >::value, T > Clamp(T val, T low, T high)
Returns the clamped value.
Definition: MathUtils-Impl.hpp:166
std::enable_if_t< std::is_arithmetic< T >::value, T > Square(T x)
Returns the square of x.
Definition: MathUtils-Impl.hpp:154
std::enable_if_t< std::is_arithmetic< T >::value > GetBarycentric(T x, size_t begin, size_t end, size_t &i, T &t)
Computes the barycentric coordinate.
Definition: MathUtils-Impl.hpp:196
std::enable_if_t< std::is_arithmetic< T >::value, size_t > ArgMin2(T x, T y)
Definition: MathUtils-Impl.hpp:116
std::enable_if_t< std::is_arithmetic< T >::value, T > Sign(T x)
Returns the sign of the value.
Definition: MathUtils-Impl.hpp:29
std::enable_if_t< std::is_arithmetic< T >::value, T > DegreesToRadians(T angleInDegrees)
Converts degrees to radians.
Definition: MathUtils-Impl.hpp:182
std::enable_if_t< std::is_arithmetic< T >::value, T > Max3(T x, T y, T z)
Returns the maximum value among three inputs.
Definition: MathUtils-Impl.hpp:46
std::enable_if_t< std::is_arithmetic< T >::value, bool > Similar(T x, T y, T eps)
Returns true if x and y are similar.
Definition: MathUtils-Impl.hpp:23
std::enable_if_t< std::is_arithmetic< T >::value, T > AbsMaxN(const T *x, size_t n)
Returns absolute maximum among n-elements.
Definition: MathUtils-Impl.hpp:103
std::enable_if_t< std::is_arithmetic< T >::value, T > AbsMinN(const T *x, size_t n)
Returns absolute minimum among n-elements.
Definition: MathUtils-Impl.hpp:90
std::enable_if_t< std::is_arithmetic< T >::value, S > BiLerp(const S &f00, const S &f10, const S &f01, const S &f11, T tx, T ty)
Computes bilinear interpolation.
Definition: MathUtils-Impl.hpp:302
Definition: pybind11Utils.hpp:20
std::enable_if_t< std::is_arithmetic< T >::value, T > Min3(T x, T y, T z)
Returns the minimum value among three inputs.
Definition: MathUtils-Impl.hpp:40
std::enable_if_t< std::is_arithmetic< T >::value, T > Cubic(T x)
Returns the cubic of x.
Definition: MathUtils-Impl.hpp:160
std::enable_if_t< std::is_arithmetic< T >::value, S > TriLerp(const S &f000, const S &f100, const S &f010, const S &f110, const S &f001, const S &f101, const S &f011, const S &f111, T tx, T ty, T tz)
Computes trilinear interpolation.
Definition: MathUtils-Impl.hpp:309
std::enable_if_t< std::is_arithmetic< T >::value, S > CatmullRom(const S &f0, const S &f1, const S &f2, const S &f3, T t)
Computes Catmull-Rom interpolation.
Definition: MathUtils-Impl.hpp:318
std::enable_if_t< std::is_arithmetic< T >::value, T > AbsMax(T x, T y)
Returns the absolute maximum value among the two inputs.
Definition: MathUtils-Impl.hpp:84
std::enable_if_t< std::is_arithmetic< T >::value, T > AbsMin(T x, T y)
Returns the absolute minimum value among the two inputs.
Definition: MathUtils-Impl.hpp:78
std::enable_if_t< std::is_arithmetic< T >::value, size_t > ArgMin3(T x, T y, T z)
Definition: MathUtils-Impl.hpp:128
std::enable_if_t< std::is_arithmetic< T >::value, T > MonotonicCatmullRom(const T &f0, const T &f1, const T &f2, const T &f3, T t)
Computes monotonic Catmull-Rom interpolation.
Definition: MathUtils-Impl.hpp:336
std::enable_if_t< std::is_arithmetic< T >::value, T > MaxN(const T *x, size_t n)
Returns maximum among n-elements.
Definition: MathUtils-Impl.hpp:65
std::enable_if_t< std::is_arithmetic< T >::value, T > RadiansToDegrees(T angleInRadians)
Converts radians to degrees.
Definition: MathUtils-Impl.hpp:189
std::enable_if_t< std::is_arithmetic< T >::value, T > MinN(const T *x, size_t n)
Returns minimum among n-elements.
Definition: MathUtils-Impl.hpp:52