[dali_2.3.26] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / public-api / math / math-utils.h
1 #ifndef DALI_MATH_UTILS_H
2 #define DALI_MATH_UTILS_H
3
4 /*
5  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <cstdint> // uint32_t
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/constants.h>
26 #include <dali/public-api/common/dali-common.h>
27
28 namespace Dali
29 {
30 /**
31  * @addtogroup dali_core_math
32  * @{
33  */
34
35 /**
36  * @brief Returns the next power of two.
37  *
38  * In case of numbers which are already a power of two this function returns the original number.
39  * If i is zero returns 1.
40  * @SINCE_1_0.0
41  * @param[in] i Input number
42  * @return The next power of two or i itself in case it's a power of two
43  */
44 inline uint32_t NextPowerOfTwo(uint32_t i)
45 {
46   DALI_ASSERT_ALWAYS(i <= 1u << (sizeof(uint32_t) * 8 - 1) && "Return type cannot represent the next power of two greater than the argument.");
47   if(i == 0u)
48   {
49     return 1u;
50   }
51
52   i--;
53   i |= i >> 1;
54   i |= i >> 2;
55   i |= i >> 4;
56   i |= i >> 8;
57   i |= i >> 16;
58   i++;
59   return i;
60 }
61
62 /**
63  * @brief Whether a number is power of two.
64  *
65  * @SINCE_1_0.0
66  * @param[in] i Input number
67  * @return    True if i is power of two.
68  */
69 inline bool IsPowerOfTwo(uint32_t i)
70 {
71   return (i != 0u) && ((i & (i - 1u)) == 0u);
72 }
73
74 /**
75  * @brief Clamp a value.
76  *
77  * @SINCE_1_0.0
78  * @param[in] value The value to clamp.
79  * @param[in] min The minimum allowed value.
80  * @param[in] max The maximum allowed value.
81  * @return T the clamped value
82  */
83 template<typename T>
84 inline const T& Clamp(const T& value, const T& min, const T& max)
85 {
86   const T& constrainedUpper         = value < max ? value : max;
87   const T& constrainedUpperAndLower = constrainedUpper > min ? constrainedUpper : min;
88   return constrainedUpperAndLower;
89 }
90
91 /**
92  * @brief Clamp a value directly.
93  *
94  * @SINCE_1_0.0
95  * @param[in,out] value The value that will be clamped.
96  * @param[in] min The minimum allowed value.
97  * @param[in] max The maximum allowed value.
98  */
99 template<typename T>
100 inline void ClampInPlace(T& value, const T& min, const T& max)
101 {
102   const T& constrainedUpper         = value < max ? value : max;
103   const T& constrainedUpperAndLower = constrainedUpper > min ? constrainedUpper : min;
104   value                             = constrainedUpperAndLower;
105 }
106
107 /**
108  * @brief Linear interpolation between two values.
109  *
110  * @SINCE_1_0.0
111  * @param[in] offset The offset through the range @p low to @p high.
112  *                   This value is clamped between 0 and 1.
113  * @param[in] low    Lowest value in range
114  * @param[in] high   Highest value in range
115  * @return A value between low and high.
116  */
117 template<typename T>
118 inline const T Lerp(const float offset, const T& low, const T& high)
119 {
120   return low + ((high - low) * Clamp(offset, 0.0f, 1.0f));
121 }
122
123 /**
124  * @brief Get an epsilon that is valid for the given range.
125  *
126  * @SINCE_1_0.0
127  * @param[in] a the first value in the range
128  * @param[in] b the second value in the range.
129  * @return a suitable epsilon
130  */
131 inline float GetRangedEpsilon(float a, float b)
132 {
133   const float   absA = fabsf(a);
134   const float   absB = fabsf(b);
135   const float   absF = absA > absB ? absA : absB;
136   const int32_t absI = static_cast<int32_t>(absF); // truncated
137
138   float epsilon = Math::MACHINE_EPSILON_10000;
139   if(absF < 0.1f)
140   {
141     return Math::MACHINE_EPSILON_0;
142   }
143   else if(absI < 2)
144   {
145     return Math::MACHINE_EPSILON_1;
146   }
147   else if(absI < 20)
148   {
149     return Math::MACHINE_EPSILON_10;
150   }
151   else if(absI < 200)
152   {
153     return Math::MACHINE_EPSILON_100;
154   }
155   else if(absI < 2000)
156   {
157     return Math::MACHINE_EPSILON_1000;
158   }
159   return epsilon;
160 }
161
162 /**
163  * @brief Helper function to compare equality of a floating point value with zero.
164  *
165  * @SINCE_1_0.0
166  * @param[in] value the value to compare
167  * @return true if the value is equal to zero
168  */
169 #if __GNUC__
170 #pragma GCC diagnostic push
171 #pragma GCC diagnostic ignored "-Wfloat-equal"
172 #endif
173 inline bool EqualsZero(float value)
174 {
175   return value == 0.0f;
176 }
177 #if __GNUC__
178 #pragma GCC diagnostic pop
179 #endif
180
181 /**
182  * @brief Helper function to compare equality of two floating point values.
183  *
184  * @SINCE_1_0.0
185  * @param[in] a the first value to compare
186  * @param[in] b the second value to compare
187  * @return true if the values are equal within a minimal epsilon for their values
188  */
189 inline bool Equals(float a, float b)
190 {
191   return (fabsf(a - b) <= GetRangedEpsilon(a, b));
192 }
193
194 /**
195  * @brief Helper function to compare equality of two floating point values.
196  *
197  * @SINCE_1_0.0
198  * @param[in] a the first value to compare
199  * @param[in] b the second value to compare
200  * @param[in] epsilon the minimum epsilon value that will be used to consider the values different
201  * @return true if the difference between the values is less than the epsilon
202  */
203 inline bool Equals(float a, float b, float epsilon)
204 {
205   return (fabsf(a - b) <= epsilon);
206 }
207
208 /**
209  * @brief Get an float that is rounded at specified place of decimals.
210  *
211  * @SINCE_1_0.0
212  * @param[in] value float value
213  * @param[in] pos decimal place
214  * @return a rounded float
215  */
216 inline float Round(float value, int32_t pos)
217 {
218   float temp;
219   temp = value * powf(10.f, static_cast<float>(pos));
220   temp = floorf(temp + 0.5f);
221   temp *= powf(10.f, static_cast<float>(-pos));
222   return temp;
223 }
224
225 /**
226  * @brief Wrap x in domain (start) to (end).
227  *
228  * This works like a floating point version
229  * of the % modulo operation. But with an offset (start).
230  *
231  * For instance a domain is specified as:
232  * start: 2
233  * end: 8
234  *
235  * @code
236  *   2                         8
237  * (\ / start)               (\ / end)
238  *   |----x                    |
239  * @endcode
240  *
241  * The value x will be confined to this domain.
242  * If x is below 2 e.g. 0, then it is wrapped to 6.
243  * If x is above or equal to 8 e.g. 8.1 then it is
244  * wrapped to 2.1.
245  *
246  * Domain wrapping is useful for various problems from
247  * calculating positions in a space that repeats, to
248  * computing angles that range from 0 to 360.
249  *
250  * @SINCE_1_0.0
251  * @param[in] x the point to be wrapped within the domain
252  * @param[in] start The start of the domain
253  * @param[in] end The end of the domain
254  *
255  * @return the wrapped value over the domain (start) (end)
256  * @note If start = end (i.e. size of domain 0), then wrapping will not occur
257  * and result will always be equal to start.
258  *
259  */
260 inline float WrapInDomain(float x, float start, float end)
261 {
262   float domain = end - start;
263   x -= start;
264
265   if(fabsf(domain) > Math::MACHINE_EPSILON_1)
266   {
267     return start + (x - floorf(x / domain) * domain);
268   }
269
270   return start;
271 }
272
273 /**
274  * @brief Find the shortest distance (magnitude) and direction (sign)
275  * from (a) to (b) in domain (start) to (end).
276  *
277  * @code
278  *  (\ / start)               (\ / end)
279  *    |-a                 b<----|
280  * @endcode
281  *
282  * Knowing the shortest distance is useful with wrapped domains
283  * to solve problems such as determining the closest object to
284  * a given point, or determining whether turning left or turning
285  * right is the shortest route to get from angle 10 degrees
286  * to angle 350 degrees (clearly in a 0-360 degree domain, turning
287  * left 20 degrees is quicker than turning right 340 degrees).
288  *
289  * The value returned holds the distance and the direction from
290  * value a to value b. For instance in the above example it would
291  * return -20. i.e. subtract 20 from current value (10) to reach
292  * target wrapped value (350).
293  *
294  * @SINCE_1_0.0
295  * @param a the current value
296  * @param b the target value
297  * @param start the start of the domain
298  * @param end the end of the domain
299  * @return the shortest direction (the sign) and distance (the magnitude)
300  * @note Assumes both (a) and (b) are already within the domain
301  * (start) to (end).
302  *
303  */
304 inline float ShortestDistanceInDomain(float a, float b, float start, float end)
305 {
306   //  (a-start + end-b)
307   float size = end - start;
308   float vect = b - a;
309
310   if(vect > 0)
311   {
312     // +ve vector, let's try perspective 1 domain to the right,
313     // and see if closer.
314     float aRight = a + size;
315     if(aRight - b < vect)
316     {
317       return b - aRight;
318     }
319   }
320   else
321   {
322     // -ve vector, let's try perspective 1 domain to the left,
323     // and see if closer.
324     float aLeft = a - size;
325     if(aLeft - b > vect)
326     {
327       return b - aLeft;
328     }
329   }
330
331   return vect;
332 }
333
334 /**
335  * @brief Extracts the sign of a number
336  *
337  * @SINCE_1_0.0
338  * @param[in] value The value we want to extract the sign
339  * @return -1 for negative values, +1 for positive values and 0 if value is 0
340  */
341 template<typename T>
342 int32_t Sign(T value)
343 {
344   return (T(0) < value) - (value < T(0));
345 }
346
347 /**
348  * @}
349  */
350 } // namespace Dali
351
352 #endif // DALI_MATH_UTILS_H