1 /***************************************************************************
2  *   Free Heroes of Might and Magic II: https://github.com/ihhub/fheroes2  *
3  *   Copyright (C) 2020                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 
21 #pragma once
22 
23 #include <cmath>
24 #include <cstdint>
25 
26 #ifndef M_PI
27 #define M_PI 3.14159265358979323846
28 #endif
29 
30 // Below source code was partially taken from https://github.com/ihhub/penguinv open source project
31 namespace fheroes2
32 {
33     // overload this function for floating types
34     template <typename _Type>
isEqual(const _Type & value1,const _Type & value2)35     bool isEqual( const _Type & value1, const _Type & value2 )
36     {
37         return ( value1 == value2 );
38     }
39 
40     template <typename _Type>
41     struct PointBase2D
42     {
PointBase2DPointBase2D43         PointBase2D()
44             : x( 0 )
45             , y( 0 )
46         {}
47 
PointBase2DPointBase2D48         PointBase2D( _Type _x, _Type _y )
49             : x( _x )
50             , y( _y )
51         {}
52 
53         bool operator==( const PointBase2D & point ) const
54         {
55             return isEqual( x, point.x ) && isEqual( y, point.y );
56         }
57 
58         bool operator!=( const PointBase2D & point ) const
59         {
60             return !( *this == point );
61         }
62 
63         PointBase2D & operator+=( const PointBase2D & point )
64         {
65             x += point.x;
66             y += point.y;
67             return *this;
68         }
69 
70         PointBase2D & operator-=( const PointBase2D & point )
71         {
72             x -= point.x;
73             y -= point.y;
74             return *this;
75         }
76 
77         PointBase2D operator+( const PointBase2D & point ) const
78         {
79             return PointBase2D( x + point.x, y + point.y );
80         }
81 
82         PointBase2D operator-( const PointBase2D & point ) const
83         {
84             return PointBase2D( x - point.x, y - point.y );
85         }
86 
87         bool operator<( const PointBase2D & point ) const
88         {
89             return x == point.x ? y < point.y : x < point.x;
90         }
91 
92         _Type x;
93         _Type y;
94     };
95 
96     template <typename _Type>
97     struct SizeBase2D
98     {
SizeBase2DSizeBase2D99         SizeBase2D()
100             : width( 0 )
101             , height( 0 )
102         {}
103 
SizeBase2DSizeBase2D104         SizeBase2D( _Type _width, _Type _height )
105             : width( _width )
106             , height( _height )
107         {}
108 
109         bool operator==( const SizeBase2D & size ) const
110         {
111             return isEqual( width, size.width ) && isEqual( height, size.height );
112         }
113 
114         bool operator!=( const SizeBase2D & size ) const
115         {
116             return !( *this == size );
117         }
118 
119         bool operator<( const SizeBase2D & size ) const
120         {
121             return width < size.width || ( width == size.width && height < size.height );
122         }
123 
124         SizeBase2D & operator+=( const SizeBase2D & size )
125         {
126             width += size.width;
127             height += size.height;
128             return *this;
129         }
130 
131         SizeBase2D & operator-=( const SizeBase2D & size )
132         {
133             width -= size.width;
134             height -= size.height;
135             return *this;
136         }
137 
138         SizeBase2D operator+( const SizeBase2D & size ) const
139         {
140             return SizeBase2D( width + size.width, height + size.height );
141         }
142 
143         SizeBase2D operator-( const SizeBase2D & size ) const
144         {
145             return SizeBase2D( width - size.width, height - size.height );
146         }
147 
148         _Type width;
149         _Type height;
150     };
151 
152     template <typename _TypePoint, typename _TypeSize>
153     struct RectBase2D
154     {
RectBase2DRectBase2D155         RectBase2D()
156             : x( 0 )
157             , y( 0 )
158             , width( 0 )
159             , height( 0 )
160         {}
161 
RectBase2DRectBase2D162         RectBase2D( _TypePoint _x, _TypePoint _y, _TypeSize _width, _TypeSize _height )
163             : x( _x )
164             , y( _y )
165             , width( _width )
166             , height( _height )
167         {}
168 
RectBase2DRectBase2D169         RectBase2D( const PointBase2D<_TypePoint> & point, const SizeBase2D<_TypeSize> & size )
170             : x( point.x )
171             , y( point.y )
172             , width( size.width )
173             , height( size.height )
174         {}
175 
176         bool operator==( const RectBase2D & rect ) const
177         {
178             return isEqual( x, rect.x ) && isEqual( y, rect.y ) && isEqual( width, rect.width ) && isEqual( height, rect.height );
179         }
180 
181         bool operator!=( const RectBase2D & rect ) const
182         {
183             return !( *this == rect );
184         }
185 
186         RectBase2D & operator+=( const PointBase2D<_TypePoint> & point )
187         {
188             x += point.x;
189             y += point.y;
190             return *this;
191         }
192 
193         RectBase2D & operator-=( const PointBase2D<_TypePoint> & point )
194         {
195             x -= point.x;
196             y -= point.y;
197             return *this;
198         }
199 
200         RectBase2D operator+( const PointBase2D<_TypePoint> & point ) const
201         {
202             return RectBase2D( x + point.x, y + point.y, width, height );
203         }
204 
205         RectBase2D operator-( const PointBase2D<_TypePoint> & point ) const
206         {
207             return RectBase2D( x - point.x, y - point.y, width, height );
208         }
209 
210         // Check whether a point within the rectangle
211         bool operator&( const PointBase2D<_TypePoint> & point ) const
212         {
213             return point.x >= x && point.y >= y && point.x < ( x + width ) && point.y < ( y + height );
214         }
215 
216         // Check whether rectangles are intersecting each other
217         bool operator&( const RectBase2D & rect ) const
218         {
219             return x <= rect.x + rect.width && rect.x <= x + width && y <= rect.y + rect.height && rect.y <= y + height;
220         }
221 
222         // Find intersection rectangle
223         RectBase2D operator^( const RectBase2D & rect ) const
224         {
225             RectBase2D output = rect;
226             if ( output.x < x ) {
227                 const _TypePoint diff = x - output.x;
228                 output.x = x;
229                 output.width -= diff;
230             }
231             if ( output.y < y ) {
232                 const _TypePoint diff = y - output.y;
233                 output.y = y;
234                 output.height -= diff;
235             }
236 
237             if ( output.x > x + width || output.y > y + height )
238                 return RectBase2D();
239 
240             if ( output.x + output.width > x + width ) {
241                 const _TypePoint diff = output.x + output.width - ( x + width );
242                 output.width -= diff;
243             }
244 
245             if ( output.y + output.height > y + height ) {
246                 const _TypePoint diff = output.y + output.height - ( y + height );
247                 output.height -= diff;
248             }
249 
250             return output;
251         }
252 
getPositionRectBase2D253         PointBase2D<_TypePoint> getPosition() const
254         {
255             return PointBase2D<_TypePoint>( x, y );
256         }
257 
258         _TypePoint x;
259         _TypePoint y;
260         _TypeSize width;
261         _TypeSize height;
262     };
263 
264     using Point = PointBase2D<int32_t>;
265     using Size = SizeBase2D<int32_t>;
266     using Rect = RectBase2D<int32_t, int32_t>;
267 }
268