1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 #ifndef utility_boxH
21 #define utility_boxH
22 
23 #include <algorithm>
24 #include <cassert>
25 
26 #include <SDL.h>
27 
28 /**
29  * An axis aligned bounding box (AABB).
30  *
31  * @tparam PointType The point type to be used in the box.
32  */
33 template<typename PointType>
34 class cBox
35 {
36 public:
37 	cBox();
38 	cBox (const PointType& minCorner, const PointType& maxCorner);
39 
40 	PointType& getMinCorner();
41 	PointType& getMaxCorner();
42 
43 	const PointType& getMinCorner() const;
44 	const PointType& getMaxCorner() const;
45 
46 	PointType getSize() const;
47 	void resize (const PointType& newSize);
48 
49 	void add (const PointType& point);
50 	void add (const cBox<PointType>& box);
51 
52 	/**
53 	 * Checks whether the point lies within the box.
54 	 *
55 	 * @param point The point to check against.
56 	 * @return True if the point is in the box.
57 	 *         False if it is outside or on the boundary of the box.
58 	 */
59 	bool within (const PointType& point) const;
60 
61 	/**
62 	 * Checks whether the point lies within the box or on its boundary.
63 	 *
64 	 * @param point The point to check against.
65 	 * @return True if the point is on the box or on the boundary of the box.
66 	 *         False if it is outside of the box.
67 	 */
68 	bool withinOrTouches (const PointType& point) const;
69 
70 	/**
71 	 * Checks whether the box intersects the other one.
72 	 *
73 	 * @param other The second box to check against.
74 	 * @return True if the other box intersects the current one.
75 	 *         False if the other box lies completely outside the current box
76 	 *         or if the two boxes only touch at their boundaries.
77 	 */
78 	bool intersects (const cBox<PointType>& other) const;
79 
80 	cBox<PointType> intersection (const cBox<PointType>& other) const;
81 
82 	SDL_Rect toSdlRect() const;
83 
84 	void fromSdlRect (const SDL_Rect& rect);
85 private:
86 	PointType minCorner;
87 	PointType maxCorner;
88 };
89 
90 //------------------------------------------------------------------------------
91 template<typename PointType>
cBox()92 cBox<PointType>::cBox()
93 {}
94 
95 //------------------------------------------------------------------------------
96 template<typename PointType>
cBox(const PointType & minCorner_,const PointType & maxCorner_)97 cBox<PointType>::cBox (const PointType& minCorner_, const PointType& maxCorner_) :
98 	minCorner (minCorner_),
99 	maxCorner (maxCorner_)
100 {}
101 
102 //------------------------------------------------------------------------------
103 template<typename PointType>
getMinCorner()104 PointType& cBox<PointType>::getMinCorner()
105 {
106 	return minCorner;
107 }
108 
109 //------------------------------------------------------------------------------
110 template<typename PointType>
getMaxCorner()111 PointType& cBox<PointType>::getMaxCorner()
112 {
113 	return maxCorner;
114 }
115 
116 //------------------------------------------------------------------------------
117 template<typename PointType>
getMinCorner()118 const PointType& cBox<PointType>::getMinCorner() const
119 {
120 	return minCorner;
121 }
122 
123 //------------------------------------------------------------------------------
124 template<typename PointType>
getMaxCorner()125 const PointType& cBox<PointType>::getMaxCorner() const
126 {
127 	return maxCorner;
128 }
129 
130 //------------------------------------------------------------------------------
131 template<typename PointType>
getSize()132 PointType cBox<PointType>::getSize() const
133 {
134 	auto diff = maxCorner - minCorner;
135 	if (std::is_integral<typename PointType::value_type>::value)
136 	{
137 		diff += 1;
138 	}
139 	return diff;
140 }
141 
142 //------------------------------------------------------------------------------
143 template<typename PointType>
resize(const PointType & newSize)144 void cBox<PointType>::resize (const PointType& newSize)
145 {
146 	maxCorner = minCorner + newSize;
147 	if (std::is_integral<typename PointType::value_type>::value)
148 	{
149 		if (std::is_unsigned<typename PointType::value_type>::value) for (size_t d = 0; d < PointType::const_size::value; ++d) assert (newSize[d] != 0);
150 		maxCorner -= 1;
151 	}
152 }
153 
154 //------------------------------------------------------------------------------
155 template<typename PointType>
add(const PointType & point)156 void cBox<PointType>::add (const PointType& point)
157 {
158 	for (size_t d = 0; d < point.size(); ++d)
159 	{
160 		minCorner[d] = std::min (minCorner[d], point[d]);
161 		maxCorner[d] = std::max (maxCorner[d], point[d]);
162 	}
163 }
164 
165 //------------------------------------------------------------------------------
166 template<typename PointType>
add(const cBox<PointType> & box)167 void cBox<PointType>::add (const cBox<PointType>& box)
168 {
169 	for (size_t d = 0; d < PointType::const_size::value; ++d)
170 	{
171 		minCorner[d] = std::min (minCorner[d], box.minCorner[d]);
172 		maxCorner[d] = std::max (maxCorner[d], box.maxCorner[d]);
173 	}
174 }
175 
176 //------------------------------------------------------------------------------
177 template<typename PointType>
within(const PointType & point)178 bool cBox<PointType>::within (const PointType& point) const
179 {
180 	for (size_t d = 0; d < point.size(); ++d)
181 	{
182 		if (point[d] <= minCorner[d] || point[d] >= maxCorner[d]) return false;
183 	}
184 	return true;
185 }
186 
187 //------------------------------------------------------------------------------
188 template<typename PointType>
withinOrTouches(const PointType & point)189 bool cBox<PointType>::withinOrTouches (const PointType& point) const
190 {
191 	for (size_t d = 0; d < point.size(); ++d)
192 	{
193 		if (point[d] < minCorner[d] || point[d] > maxCorner[d]) return false;
194 	}
195 	return true;
196 }
197 
198 //------------------------------------------------------------------------------
199 template<typename PointType>
intersects(const cBox<PointType> & other)200 bool cBox<PointType>::intersects (const cBox<PointType>& other) const
201 {
202 	for (size_t d = 0; d < PointType::const_size::value; ++d)
203 	{
204 		if (std::min (maxCorner[d], other.getMaxCorner()[d]) < std::max (minCorner[d], other.getMinCorner()[d])) return false;
205 	}
206 	return true;
207 }
208 
209 //------------------------------------------------------------------------------
210 template<typename PointType>
intersection(const cBox<PointType> & other)211 cBox<PointType> cBox<PointType>::intersection (const cBox<PointType>& other) const
212 {
213 	assert (intersects (other));
214 
215 	cBox<PointType> result;
216 	for (size_t d = 0; d < PointType::const_size::value; ++d)
217 	{
218 		result.getMinCorner()[d] = std::max (minCorner[d], other.getMinCorner()[d]);
219 		result.getMaxCorner()[d] = std::min (maxCorner[d], other.getMaxCorner()[d]);
220 	}
221 	return result;
222 }
223 
224 //------------------------------------------------------------------------------
225 template<typename PointType>
toSdlRect()226 SDL_Rect cBox<PointType>::toSdlRect() const
227 {
228 	static_assert (PointType::const_size::value == 2, "Converting to SDL_Rect not support in dimension other than 2.");
229 	static_assert (std::is_same<typename PointType::value_type, int>::value, "Converting to SDL_Rect not support if point scalar value is other than int."); // NOTE: we may could allow all non-narrowing casts here (e.g. short to int).
230 
231 	const auto diff = getSize();
232 
233 	SDL_Rect result = {minCorner[0], minCorner[1], diff[0], diff[1]};
234 	return result;
235 }
236 
237 //------------------------------------------------------------------------------
238 template<typename PointType>
fromSdlRect(const SDL_Rect & rect)239 void cBox<PointType>::fromSdlRect (const SDL_Rect& rect)
240 {
241 	minCorner[0] = rect.x;
242 	minCorner[1] = rect.y;
243 
244 	maxCorner[0] = rect.x + rect.w - 1;
245 	maxCorner[1] = rect.y + rect.h - 1;
246 }
247 
248 #endif // utility_boxH
249