c++17 move operators etc. for the Math classes
[platform/core/uifw/dali-core.git] / dali / public-api / math / rect.h
1 #ifndef DALI_RECT_H
2 #define DALI_RECT_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 <math.h>
23 #include <ostream>
24
25 // INTERNAL INCLUDES
26 #include <dali/public-api/math/math-utils.h>
27
28 namespace Dali
29 {
30 /**
31  * @addtogroup dali_core_math
32  * @{
33  */
34
35 /**
36  * @brief Template class to create and operate on rectangles.
37  * @SINCE_1_0.0
38  */
39
40 template< typename T = float >
41 struct Rect
42 {
43 // Methods
44
45   /**
46    * @brief Constructor.
47    * @SINCE_1_0.0
48    */
49   Rect()
50   : x(0),
51     y(0),
52     width(0),
53     height(0)
54   {
55   }
56
57   /**
58    * @brief Constructor.
59    *
60    * @SINCE_1_0.0
61    * @param[in] x      X coordinate (or left)
62    * @param[in] y      Y coordinate (or right)
63    * @param[in] width  Width (or bottom)
64    * @param[in] height Height (or top)
65    */
66   Rect(T x, T y, T width, T height)
67   : x(x),
68     y(y),
69     width(width),
70     height(height)
71   {
72   }
73
74   /**
75    * @brief Conversion constructor from Vector4.
76    *
77    * @SINCE_1_9.14
78    * @param[in] vec4 Vector4 to convert from
79    */
80   Rect( const Vector4& vec4 )
81   : x(vec4.x),
82     y(vec4.y),
83     width(vec4.z),
84     height(vec4.w)
85   {
86   }
87
88   /**
89    * @brief Copy constructor.
90    *
91    * @SINCE_1_0.0
92    * @param[in] rhs The original object
93    */
94   Rect(const Rect<T>& rhs)
95   {
96     x = rhs.x;
97     y = rhs.y;
98     width = rhs.width;
99     height = rhs.height;
100   }
101
102   /**
103    * @brief Copy assignment operator.
104    *
105    * @SINCE_1_0.0
106    * @param[in] rhs The original object
107    * @return Reference to this
108    */
109   Rect<T>& operator= (const Rect<T>& rhs)
110   {
111     if (this != &rhs)
112     {
113       x = rhs.x;
114       y = rhs.y;
115       width = rhs.width;
116       height = rhs.height;
117     }
118
119     return *this;
120   }
121
122   /**
123    * @brief Move constructor.
124    *
125    * @SINCE_1_9.21
126    * @param[in] rhs The original object
127    */
128   Rect<T>( Rect<T>&& rhs )
129   : x( rhs.x ),
130     y( rhs.y ),
131     width( rhs.width ),
132     height( rhs.height )
133   {
134   }
135
136   /**
137    * @brief Move assignment operator.
138    *
139    * @SINCE_1_9.21
140    * @param[in] rhs The original object
141    * @return Reference to this
142    */
143   Rect<T>& operator=( Rect<T>&& rhs )
144   {
145     if (this != &rhs)
146     {
147       x = rhs.x;
148       y = rhs.y;
149       width = rhs.width;
150       height = rhs.height;
151     }
152
153     return *this;
154   }
155
156   /**
157    * @brief Assignment operator.
158    *
159    * @SINCE_1_9.14
160    * @param[in] vec4 The Vector4 to assign
161    * @return Reference to this
162    */
163   Rect<T>& operator= (const Vector4& vec4)
164   {
165     x = vec4.x;
166     y = vec4.y;
167     width = vec4.z;
168     height = vec4.w;
169
170     return *this;
171   }
172
173   /**
174    * @brief Assignment from individual values.
175    *
176    * @SINCE_1_0.0
177    * @param[in] newX      X coordinate
178    * @param[in] newY      Y coordinate
179    * @param[in] newWidth  Width
180    * @param[in] newHeight Height
181    */
182   void Set(T newX, T newY, T newWidth, T newHeight)
183   {
184     x = newX;
185     y = newY;
186     width = newWidth;
187     height = newHeight;
188   }
189
190   /**
191    * @brief Determines whether or not this Rectangle is empty.
192    *
193    * @SINCE_1_0.0
194    * @return True if width or height are zero
195    */
196   bool IsEmpty() const
197   {
198     return width  == 0 ||
199       height == 0;
200   }
201
202   /**
203    * @brief Determines whether or not this Rectangle is valid.
204    *
205    * @SINCE_1_9.18
206    * @return True if width and height are not negative
207    */
208   bool IsValid() const
209   {
210     return !(width < 0 || height < 0);
211   }
212
213   /**
214    * @brief Gets the left of the rectangle.
215    *
216    * @SINCE_1_0.0
217    * @return The left edge of the rectangle
218    */
219   T Left() const
220   {
221     return x;
222   }
223   /**
224    * @brief Gets the right of the rectangle.
225    *
226    * @SINCE_1_0.0
227    * @return The right edge of the rectangle
228    */
229   T Right() const
230   {
231     return x + width;
232   }
233
234   /**
235    * @brief Gets the top of the rectangle.
236    *
237    * @SINCE_1_0.0
238    * @return The top of the rectangle
239    */
240   T Top() const
241   {
242     return y;
243   }
244
245   /**
246    * @brief Gets the bottom of the rectangle.
247    *
248    * @SINCE_1_0.0
249    * @return The bottom of the rectangle
250    */
251   T Bottom() const
252   {
253     return y + height;
254   }
255
256   /**
257    * @brief Gets the area of the rectangle.
258    *
259    * @SINCE_1_0.0
260    * @return The area of the rectangle
261    */
262   T Area() const
263   {
264     return width * height;
265   }
266
267   /**
268    * @brief Determines whether or not this rectangle and the specified rectangle intersect.
269    *
270    * @SINCE_1_0.0
271    * @param[in] other The other rectangle to test against this rectangle
272    * @return True if the rectangles intersect
273    */
274   bool Intersects(const Rect<T>& other) const
275   {
276     return (other.x + other.width) > x && other.x < (x + width) &&
277       (other.y + other.height) > y && other.y < (y + height);
278   }
279
280   /**
281    * @brief Intersects this rectangle and the specified rectangle.
282    * The result of the intersection is stored in this rectangle.
283    *
284    * @SINCE_1_9.18
285    * @param[in] rect The other rectangle to intersect with
286    * @return True if the rectangles intersect
287    */
288   bool Intersect(const Rect<T>& rect)
289   {
290     const int left = std::max(rect.x, x);
291     const int top = std::max(rect.y, y);
292     const int right = std::min(rect.x + rect.width, x + width);
293     const int bottom = std::min(rect.y + rect.height, y + height);
294
295     const int width = right - left;
296     const int height = bottom - top;
297     if (!(width < 0 || height < 0))
298     {
299       x = left;
300       y = top;
301       this->width = width;
302       this->height = height;
303       return true;
304     }
305
306     return false;
307   }
308
309   /**
310    * @brief Merges this rectangle and the specified rectangle.
311    * The result of the merge is stored in this rectangle.
312    *
313    * @SINCE_1_9.18
314    * @param[in] rect The other rectangle to merge with
315    */
316   void Merge(const Rect<T>& rect)
317   {
318     const int left = std::min(rect.x, x);
319     const int top = std::min(rect.y, y);
320     const int right = std::max(rect.x + rect.width, x + width);
321     const int bottom = std::max(rect.y + rect.height, y + height);
322     x = left;
323     y = top;
324     width = right - left;
325     height = bottom - top;
326   }
327
328   /**
329    * @brief Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards.
330    * If dx is negative, then the sides are moved outwards.
331    * The result of the inset is stored in this rectangle.
332    * @SINCE_1_9.18
333    */
334   void Inset(T dx, T dy)
335   {
336     const int left = x - dx;
337     const int top = y - dy;
338     const int right = x + width + dx;
339     const int bottom = y + height + dy;
340     x = left;
341     y = top;
342     width = right - left;
343     height = bottom - top;
344   }
345
346   /**
347    * @brief Determines whether or not this Rectangle contains the specified rectangle.
348    *
349    * @SINCE_1_0.0
350    * @param[in] other The other rectangle to test against this rectangle
351    * @return True if the specified rectangle is contained
352    */
353   bool Contains(const Rect<T>& other) const
354   {
355     return other.x >= x && (other.x + other.width)  <= (x + width) &&
356       other.y >= y && (other.y + other.height) <= (y + height);
357   }
358
359 public:   // Data
360
361   union
362   {
363     T x;      ///< X position of the rectangle
364     T left;   ///< The left value
365   };
366
367   union
368   {
369     T y;      ///< Y position of the rectangle
370     T right;  ///< The right value
371   };
372
373   union
374   {
375     T width;  ///< width of the rectangle
376     T bottom; ///< The bottom value
377   };
378
379   union
380   {
381     T height; ///< height of the rectangle
382     T top;    ///< The top value
383   };
384 };
385
386 /**
387  * @brief Equality operator.
388  *
389  * @SINCE_1_0.0
390  * @param[in] lhs First operand
391  * @param[in] rhs Second operand
392  * @return True if boxes are exactly same
393  */
394 template< typename T >
395 inline bool operator==( const Rect<T>& lhs, const Rect<T>& rhs )
396 {
397   return ( lhs.x == rhs.x )&&
398     ( lhs.y == rhs.y )&&
399     ( lhs.width == rhs.width )&&
400     ( lhs.height == rhs.height );
401 }
402
403 /**
404  * @brief Inequality operator.
405  *
406  * @SINCE_1_0.0
407  * @param[in] lhs The first rectangle
408  * @param[in] rhs The second rectangle
409  * @return True if rectangles are not identical
410  */
411 template< typename T >
412 inline bool operator!=( const Rect<T>& lhs, const Rect<T>& rhs )
413 {
414   return !(lhs == rhs);
415 }
416
417 /**
418  * @brief Equality operator specialization for float.
419  *
420  * @SINCE_1_0.0
421  * @param[in] lhs The first rectangle
422  * @param[in] rhs The second rectangle
423  * @return True if rectangles are exactly same
424  */
425 template<>
426 inline bool operator==( const Rect<float>& lhs, const Rect<float>& rhs )
427 {
428   return ( fabsf( lhs.x - rhs.x ) < GetRangedEpsilon(lhs.x, rhs.x) )&&
429     ( fabsf( lhs.y - rhs.y ) < GetRangedEpsilon(lhs.y, rhs.y) )&&
430     ( fabsf( lhs.width - rhs.width ) < GetRangedEpsilon(lhs.width, rhs.width) )&&
431     ( fabsf( lhs.height - rhs.height ) < GetRangedEpsilon(lhs.height, rhs.height) );
432 }
433
434 /**
435  * @brief IsEmpty specialization for float.
436  *
437  * @SINCE_1_0.0
438  * @return True if the rectangle has zero size
439  */
440 template<>
441 inline bool Rect<float>::IsEmpty() const
442 {
443   return (fabsf(width)  <= GetRangedEpsilon(width, width)
444           ||
445           fabsf(height) <= GetRangedEpsilon(height, height));
446 }
447
448 /**
449  * @brief Converts the value of the rectangle into a string and insert in to an output stream.
450  *
451  * @SINCE_1_0.0
452  * @param[in] stream The output stream operator
453  * @param[in] rectangle the rectangle to output
454  * @return The output stream operator
455  */
456 template< typename T >
457 inline std::ostream& operator<< (std::ostream& stream, const Rect<T>& rectangle)
458 {
459   return stream << "[" << rectangle.x << ", " << rectangle.y << ", " << rectangle.width << ", " << rectangle.height << "]";
460 }
461
462 /**
463  * @}
464  */
465 } // namespace Dali
466
467 #endif // DALI_RECT_H