[dali_1.0.15] Merge branch 'tizen'
[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) 2014 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 <algorithm> // std::min & max
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 /**
32  * @brief Returns the next power of two.
33  *
34  * In case of numbers which are already a power of two this function returns the original number.
35  * If i is zero returns 1
36  * @param[in] i input number
37  * @return    next power of two or i itself in case it's a power of two
38  */
39 inline unsigned int NextPowerOfTwo( unsigned int i )
40 {
41   DALI_ASSERT_DEBUG(i <= 1U << (sizeof(unsigned) * 8 - 1) && "Return type cannot represent the next power of two greater than the argument.");
42   if(i==0)
43   {
44     return 1;
45   }
46
47   i--;
48   i |= i >> 1;
49   i |= i >> 2;
50   i |= i >> 4;
51   i |= i >> 8;
52   i |= i >> 16;
53   i++;
54   return i;
55 }
56
57 /**
58  * @brief Whether a number is power of two.
59  *
60  * @param[in] i input number
61  * @return    true if i is power of two
62  */
63 inline bool IsPowerOfTwo( unsigned int i )
64 {
65   return (i != 0) && ((i & (i - 1)) == 0);
66 }
67
68 /**
69  * @brief Clamp a value.
70  *
71  * @param[in] value The value to clamp.
72  * @param[in] min The minimum allowed value.
73  * @param[in] max The maximum allowed value.
74  * @return T the clamped value
75  */
76 template< typename T >
77 inline const T& Clamp( const T& value, const T& min, const T& max )
78 {
79   return std::max( std::min( value, max ), min );
80 }
81
82 /**
83  * @brief Clamp a value directly.
84  *
85  * @param[in,out] value The value that will be clamped.
86  * @param[in] min The minimum allowed value.
87  * @param[in] max The maximum allowed value.
88  */
89 template< typename T >
90 inline void ClampInPlace( T& value, const T& min, const T& max )
91 {
92   value =  std::max( std::min( value, max ), min );
93 }
94
95
96 /**
97  * @brief Linear interpolation between two values.
98  *
99  * @param[in] offset The offset through the range @p low to @p high.
100  *                   This value is clamped between 0 and 1
101  * @param[in] low    Lowest value in range
102  * @param[in] high   Highest value in range
103  * @return A value between low and high.
104  */
105 template< typename T >
106 inline const T Lerp( const float offset, const T& low, const T& high )
107 {
108   return low + ((high - low) * Clamp(offset, 0.0f, 1.0f));
109 }
110
111 /**
112  * @brief Get an epsilon that is valid for the given range.
113  *
114  * @param[in] a the first value in the range
115  * @param[in] b the second value in the range.
116  * @return a suitable epsilon
117  */
118 inline float GetRangedEpsilon(float a, float b)
119 {
120   float abs_f = std::max(fabsf(a), fabsf(b));
121   int abs_i = (int) abs_f;
122
123   float epsilon = Math::MACHINE_EPSILON_10000;
124   if (abs_f < 0.1f)
125   {
126     return Math::MACHINE_EPSILON_0;
127   }
128   else if (abs_i < 2)
129   {
130     return Math::MACHINE_EPSILON_1;
131   }
132   else if (abs_i < 20)
133   {
134     return Math::MACHINE_EPSILON_10;
135   }
136   else if (abs_i < 200)
137   {
138     return Math::MACHINE_EPSILON_100;
139   }
140   else if (abs_i < 2000)
141   {
142     return Math::MACHINE_EPSILON_1000;
143   }
144   return epsilon;
145 }
146
147 /**
148  * @brief Helper function to compare equality of a floating point value with zero.
149  *
150  * @param[in] value the value to compare
151  * @return true if the value is equal to zero
152  */
153 #pragma GCC diagnostic push
154 #pragma GCC diagnostic ignored "-Wfloat-equal"
155 inline bool EqualsZero( float value )
156 {
157   return value == 0.0f;
158 }
159 #pragma GCC diagnostic pop
160
161 /**
162  * @brief Helper function to compare equality of two floating point values.
163  *
164  * @param[in] a the first value to compare
165  * @param[in] b the second value to compare
166  * @return true if the values are equal within a minimal epsilon for their values
167  */
168 inline bool Equals( float a, float b )
169 {
170   return ( fabsf( a - b ) <= GetRangedEpsilon( a, b ) );
171 }
172
173 /**
174  * @brief Helper function to compare equality of two floating point values.
175  *
176  * @param[in] a the first value to compare
177  * @param[in] b the second value to compare
178  * @param[in] epsilon the minimum epsilon value that will be used to consider the values different
179  * @return true if the difference between the values is less than the epsilon
180  */
181 inline bool Equals( float a, float b, float epsilon )
182 {
183   return ( fabsf( a - b ) <= epsilon );
184 }
185
186 /**
187  * @brief Get an float that is rounded at specified place of decimals.
188  *
189  * @param[in] value float value
190  * @param[in] pos decimal place
191  * @return a rounded float
192  */
193 inline float Round(float value, int pos)
194 {
195   float temp;
196   temp = value * powf( 10, pos );
197   temp = floorf( temp + 0.5 );
198   temp *= powf( 10, -pos );
199   return temp;
200 }
201
202 /**
203  * @brief Wrap x in domain (start) to (end).
204  *
205  * This works like a floating point version
206  * of the % modulo operation. But with an offset (start).
207  *
208  * For instance a domain is specified as:
209  * start: 2
210  * end: 8
211  *
212  *   2                         8
213  * (\ / start)               (\ / end)
214  *   |----x                    |
215  *
216  * The value x will be confined to this domain.
217  * If x is below 2 e.g. 0, then it is wraped to 6.
218  * If x is above or equal to 8 e.g. 8.1 then it is
219  * wrapped to 2.1
220  *
221  * Domain wrapping is useful for various problems from
222  * calculating positions in a space that repeats, to
223  * computing angles that range from 0 to 360.
224  *
225  * @param[in] x the point to be wrapped within the domain
226  * @param[in] start The start of the domain
227  * @param[in] end The end of the domain
228  *
229  * @note if start = end (i.e. size of domain 0), then wrapping will not occur
230  * and result will always be equal to start.
231  *
232  * @return the wrapped value over the domain (start) (end)
233  */
234 inline float WrapInDomain(float x, float start, float end)
235 {
236   float domain = end - start;
237   x -= start;
238
239   if(fabsf(domain) > Math::MACHINE_EPSILON_1)
240   {
241     return start + (x - floorf(x / domain) * domain);
242   }
243
244   return start;
245 }
246
247
248 /**
249  * @brief Find the shortest distance (magnitude) and direction (sign)
250  * from (a) to (b) in domain (start) to (end).
251  *
252  * (\ / start)               (\ / end)
253  *   |-a                 b<----|
254  *
255  * Knowing the shortest distance is useful with wrapped domains
256  * to solve problems such as determing the closest object to
257  * a given point, or determing whether turning left or turning
258  * right is the shortest route to get from angle 10 degrees
259  * to angle 350 degrees (clearly in a 0-360 degree domain, turning
260  * left 20 degrees is quicker than turning right 340 degrees).
261  *
262  * The value returned holds the distance and the direction from
263  * value a to value b. For instance in the above example it would
264  * return -20. i.e. subtract 20 from current value (10) to reach
265  * target wrapped value (350).
266  *
267  * @note assumes both (a) and (b) are already within the domain
268  * (start) to (end)
269  *
270  * @param a the current value
271  * @param b the target value
272  * @param start the start of the domain
273  * @param end the end of the domain
274  * @return the shortest direction (the sign) and distance (the magnitude)
275  */
276 inline float ShortestDistanceInDomain( float a, float b, float start, float end )
277 {
278   //  (a-start + end-b)
279   float size = end-start;
280   float vect = b-a;
281
282   if(vect > 0)
283   {
284     // +ve vector, let's try perspective 1 domain to the right,
285     // and see if closer.
286     float aRight = a+size;
287     if( aRight-b < vect )
288     {
289       return b-aRight;
290     }
291   }
292   else
293   {
294     // -ve vector, let's try perspective 1 domain to the left,
295     // and see if closer.
296     float aLeft = a-size;
297     if( aLeft-b > vect )
298     {
299       return b-aLeft;
300     }
301   }
302
303   return vect;
304 }
305
306 } // namespace Dali
307
308 #endif // __DALI_MATH_UTILS_H__