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