55024c758fe8544b015dd915cd211a96951e71fb
[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) 2019 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/dali-common.h>
26 #include <dali/public-api/common/constants.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 /**
109  * @brief Linear interpolation between two values.
110  *
111  * @SINCE_1_0.0
112  * @param[in] offset The offset through the range @p low to @p high.
113  *                   This value is clamped between 0 and 1.
114  * @param[in] low    Lowest value in range
115  * @param[in] high   Highest value in range
116  * @return A value between low and high.
117  */
118 template< typename T >
119 inline const T Lerp( const float offset, const T& low, const T& high )
120 {
121   return low + ((high - low) * Clamp(offset, 0.0f, 1.0f));
122 }
123
124 /**
125  * @brief Get an epsilon that is valid for the given range.
126  *
127  * @SINCE_1_0.0
128  * @param[in] a the first value in the range
129  * @param[in] b the second value in the range.
130  * @return a suitable epsilon
131  */
132 inline float GetRangedEpsilon( float a, float b )
133 {
134   const float absA = fabsf( a );
135   const float absB = fabsf( b );
136   const float absF = absA > absB ? absA : absB;
137   const int32_t absI = static_cast<int32_t>( absF ); // truncated
138
139   float epsilon = Math::MACHINE_EPSILON_10000;
140   if (absF < 0.1f)
141   {
142     return Math::MACHINE_EPSILON_0;
143   }
144   else if (absI < 2)
145   {
146     return Math::MACHINE_EPSILON_1;
147   }
148   else if (absI < 20)
149   {
150     return Math::MACHINE_EPSILON_10;
151   }
152   else if (absI < 200)
153   {
154     return Math::MACHINE_EPSILON_100;
155   }
156   else if (absI < 2000)
157   {
158     return Math::MACHINE_EPSILON_1000;
159   }
160   return epsilon;
161 }
162
163 /**
164  * @brief Helper function to compare equality of a floating point value with zero.
165  *
166  * @SINCE_1_0.0
167  * @param[in] value the value to compare
168  * @return true if the value is equal to zero
169  */
170 #if __GNUC__
171 #pragma GCC diagnostic push
172 #pragma GCC diagnostic ignored "-Wfloat-equal"
173 #endif
174 inline bool EqualsZero( float value )
175 {
176   return value == 0.0f;
177 }
178 #if __GNUC__
179 #pragma GCC diagnostic pop
180 #endif
181
182 /**
183  * @brief Helper function to compare equality of two floating point values.
184  *
185  * @SINCE_1_0.0
186  * @param[in] a the first value to compare
187  * @param[in] b the second value to compare
188  * @return true if the values are equal within a minimal epsilon for their values
189  */
190 inline bool Equals( float a, float b )
191 {
192   return ( fabsf( a - b ) <= GetRangedEpsilon( a, b ) );
193 }
194
195 /**
196  * @brief Helper function to compare equality of two floating point values.
197  *
198  * @SINCE_1_0.0
199  * @param[in] a the first value to compare
200  * @param[in] b the second value to compare
201  * @param[in] epsilon the minimum epsilon value that will be used to consider the values different
202  * @return true if the difference between the values is less than the epsilon
203  */
204 inline bool Equals( float a, float b, float epsilon )
205 {
206   return ( fabsf( a - b ) <= epsilon );
207 }
208
209 /**
210  * @brief Get an float that is rounded at specified place of decimals.
211  *
212  * @SINCE_1_0.0
213  * @param[in] value float value
214  * @param[in] pos decimal place
215  * @return a rounded float
216  */
217 inline float Round( float value, int32_t pos )
218 {
219   float temp;
220   temp = value * powf( 10.f, static_cast<float>( pos ) );
221   temp = floorf( temp + 0.5f );
222   temp *= powf( 10.f, static_cast<float>( -pos ) );
223   return temp;
224 }
225
226 /**
227  * @brief Wrap x in domain (start) to (end).
228  *
229  * This works like a floating point version
230  * of the % modulo operation. But with an offset (start).
231  *
232  * For instance a domain is specified as:
233  * start: 2
234  * end: 8
235  *
236  * @code
237  *   2                         8
238  * (\ / start)               (\ / end)
239  *   |----x                    |
240  * @endcode
241  *
242  * The value x will be confined to this domain.
243  * If x is below 2 e.g. 0, then it is wrapped to 6.
244  * If x is above or equal to 8 e.g. 8.1 then it is
245  * wrapped to 2.1.
246  *
247  * Domain wrapping is useful for various problems from
248  * calculating positions in a space that repeats, to
249  * computing angles that range from 0 to 360.
250  *
251  * @SINCE_1_0.0
252  * @param[in] x the point to be wrapped within the domain
253  * @param[in] start The start of the domain
254  * @param[in] end The end of the domain
255  *
256  * @return the wrapped value over the domain (start) (end)
257  * @note If start = end (i.e. size of domain 0), then wrapping will not occur
258  * and result will always be equal to start.
259  *
260  */
261 inline float WrapInDomain(float x, float start, float end)
262 {
263   float domain = end - start;
264   x -= start;
265
266   if(fabsf(domain) > Math::MACHINE_EPSILON_1)
267   {
268     return start + (x - floorf(x / domain) * domain);
269   }
270
271   return start;
272 }
273
274
275 /**
276  * @brief Find the shortest distance (magnitude) and direction (sign)
277  * from (a) to (b) in domain (start) to (end).
278  *
279  * @code
280  *  (\ / start)               (\ / end)
281  *    |-a                 b<----|
282  * @endcode
283  *
284  * Knowing the shortest distance is useful with wrapped domains
285  * to solve problems such as determining the closest object to
286  * a given point, or determining whether turning left or turning
287  * right is the shortest route to get from angle 10 degrees
288  * to angle 350 degrees (clearly in a 0-360 degree domain, turning
289  * left 20 degrees is quicker than turning right 340 degrees).
290  *
291  * The value returned holds the distance and the direction from
292  * value a to value b. For instance in the above example it would
293  * return -20. i.e. subtract 20 from current value (10) to reach
294  * target wrapped value (350).
295  *
296  * @SINCE_1_0.0
297  * @param a the current value
298  * @param b the target value
299  * @param start the start of the domain
300  * @param end the end of the domain
301  * @return the shortest direction (the sign) and distance (the magnitude)
302  * @note Assumes both (a) and (b) are already within the domain
303  * (start) to (end).
304  *
305  */
306 inline float ShortestDistanceInDomain( float a, float b, float start, float end )
307 {
308   //  (a-start + end-b)
309   float size = end-start;
310   float vect = b-a;
311
312   if(vect > 0)
313   {
314     // +ve vector, let's try perspective 1 domain to the right,
315     // and see if closer.
316     float aRight = a+size;
317     if( aRight-b < vect )
318     {
319       return b-aRight;
320     }
321   }
322   else
323   {
324     // -ve vector, let's try perspective 1 domain to the left,
325     // and see if closer.
326     float aLeft = a-size;
327     if( aLeft-b > vect )
328     {
329       return b-aLeft;
330     }
331   }
332
333   return vect;
334 }
335
336 /**
337  * @brief Extracts the sign of a number
338  *
339  * @SINCE_1_0.0
340  * @param[in] value The value we want to extract the sign
341  * @return -1 for negative values, +1 for positive values and 0 if value is 0
342  */
343 template <typename T>
344 int32_t Sign( T value )
345 {
346   return ( T(0) < value ) - ( value < T(0) );
347 }
348
349 /**
350  * @}
351  */
352 } // namespace Dali
353
354 #endif // DALI_MATH_UTILS_H