1 /*
2   libSDL2pp - C++11 bindings/wrapper for SDL2
3   Copyright (C) 2013-2015 Dmitry Marakasov <amdmi3@amdmi3.ru>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #ifndef SDL2PP_RECT_HH
23 #define SDL2PP_RECT_HH
24 
25 #include <functional>
26 
27 #include <SDL_rect.h>
28 
29 #include <SDL2pp/Optional.hh>
30 #include <SDL2pp/Point.hh>
31 #include <SDL2pp/Export.hh>
32 
33 namespace SDL2pp {
34 
35 ////////////////////////////////////////////////////////////
36 /// \brief 2D rectangle
37 ///
38 /// \ingroup geometry
39 ///
40 /// \headerfile SDL2pp/Rect.hh
41 ///
42 /// This class is public-derived from SDL_Rect structure,
43 /// may generally used as it if passed via pointer or
44 /// reference. It also supports direct access to x, y, w
45 /// and h members.
46 ///
47 /// \see http://wiki.libsdl.org/SDL_Rect
48 ///
49 ////////////////////////////////////////////////////////////
50 class SDL2PP_EXPORT Rect : public SDL_Rect {
51 public:
52 	////////////////////////////////////////////////////////////
53 	/// \brief Default constructor
54 	///
55 	/// Creates a Rect(0, 0, 0, 0)
56 	///
57 	////////////////////////////////////////////////////////////
Rect()58 	constexpr Rect() : SDL_Rect{0, 0, 0, 0} {
59 	}
60 
61 	////////////////////////////////////////////////////////////
62 	/// \brief Construct a rect from existing SDL_Rect
63 	///
64 	/// \param[in] rect Existing SDL_Rect
65 	///
66 	////////////////////////////////////////////////////////////
Rect(const SDL_Rect & rect)67 	constexpr Rect(const SDL_Rect& rect) : SDL_Rect{rect.x, rect.y, rect.w, rect.h} {
68 	}
69 
70 	////////////////////////////////////////////////////////////
71 	/// \brief Construct the rect from given corner coordinates, and size
72 	///
73 	/// \param[in] corner Coordinates of the top left rectangle corner
74 	/// \param[in] size Dimensions of the rectangle
75 	///
76 	////////////////////////////////////////////////////////////
Rect(const Point & corner,const Point & size)77 	constexpr Rect(const Point& corner, const Point& size) : SDL_Rect{corner.x, corner.y, size.x, size.y} {
78 	}
79 
80 	////////////////////////////////////////////////////////////
81 	/// \brief Construct the rect from given corner coordinates, width and height
82 	///
83 	/// \param[in] x X coordinate of the top left rectangle corner
84 	/// \param[in] y Y coordinate of the top left rectangle corner
85 	/// \param[in] w Width of the rectangle
86 	/// \param[in] h Height of the rectangle
87 	///
88 	////////////////////////////////////////////////////////////
Rect(int x,int y,int w,int h)89 	constexpr Rect(int x, int y, int w, int h) : SDL_Rect{x, y, w, h} {
90 	}
91 
92 	////////////////////////////////////////////////////////////
93 	/// \brief Construct the rect from given center coordinates, width and height
94 	///
95 	/// \param[in] cx X coordinate of the rectangle center
96 	/// \param[in] cy Y coordinate of the rectangle center
97 	/// \param[in] w Width of the rectangle
98 	/// \param[in] h Height of the rectangle
99 	///
100 	////////////////////////////////////////////////////////////
FromCenter(int cx,int cy,int w,int h)101 	static constexpr Rect FromCenter(int cx, int cy, int w, int h) {
102 		return Rect(cx - w/2, cy - h/2, w, h);
103 	}
104 
105 	////////////////////////////////////////////////////////////
106 	/// \brief Construct the rect from given center coordinates and size
107 	///
108 	/// \param[in] center Coordinates of the rectangle center
109 	/// \param[in] size Dimensions of the rectangle
110 	///
111 	////////////////////////////////////////////////////////////
FromCenter(const Point & center,const Point & size)112 	static constexpr Rect FromCenter(const Point& center, const Point& size) {
113 		return Rect(center - size / 2, size);
114 	}
115 
116 	////////////////////////////////////////////////////////////
117 	/// \brief Construct the rect from given corners coordinates
118 	///
119 	/// \param[in] x1 X coordinate of the top left rectangle corner
120 	/// \param[in] y1 Y coordinate of the top left rectangle corner
121 	/// \param[in] x2 X coordinate of the bottom right rectangle corner
122 	/// \param[in] y2 Y coordinate of the bottom right rectangle corner
123 	///
124 	////////////////////////////////////////////////////////////
FromCorners(int x1,int y1,int x2,int y2)125 	static constexpr Rect FromCorners(int x1, int y1, int x2, int y2) {
126 		return Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
127 	}
128 
129 	////////////////////////////////////////////////////////////
130 	/// \brief Construct the rect from given centers coordinates
131 	///
132 	/// \param[in] p1 Coordinates of the top left rectangle corner
133 	/// \param[in] p2 Coordinates of the bottom right rectangle corner
134 	///
135 	////////////////////////////////////////////////////////////
FromCorners(const Point & p1,const Point & p2)136 	static constexpr Rect FromCorners(const Point& p1, const Point& p2) {
137 		return Rect(p1, p2 - p1 + Point(1, 1));
138 	}
139 
140 	////////////////////////////////////////////////////////////
141 	/// \brief Copy constructor
142 	///
143 	////////////////////////////////////////////////////////////
144 	Rect(const Rect&) noexcept = default;
145 
146 	////////////////////////////////////////////////////////////
147 	/// \brief Move constructor
148 	///
149 	////////////////////////////////////////////////////////////
150 	Rect(Rect&&) noexcept = default;
151 
152 	////////////////////////////////////////////////////////////
153 	/// \brief Assignment operator
154 	///
155 	/// \returns Reference to self
156 	///
157 	////////////////////////////////////////////////////////////
158 	Rect& operator=(const Rect&) noexcept = default;
159 
160 	////////////////////////////////////////////////////////////
161 	/// \brief Move assignment operator
162 	///
163 	/// \returns Reference to self
164 	///
165 	////////////////////////////////////////////////////////////
166 	Rect& operator=(Rect&&) noexcept = default;
167 
168 	////////////////////////////////////////////////////////////
169 	/// \brief Get X coordinate of the rect corner
170 	///
171 	/// \returns X coordinate of the rect corner
172 	///
173 	////////////////////////////////////////////////////////////
GetX() const174 	constexpr int GetX() const {
175 		return x;
176 	}
177 
178 	////////////////////////////////////////////////////////////
179 	/// \brief Set X coordinate of the rect corner
180 	///
181 	/// \param[in] nx New X coordinate value
182 	///
183 	/// \returns Reference to self
184 	///
185 	////////////////////////////////////////////////////////////
SetX(int nx)186 	Rect& SetX(int nx) {
187 		x = nx;
188 		return *this;
189 	}
190 
191 	////////////////////////////////////////////////////////////
192 	/// \brief Get Y coordinate of the rect corner
193 	///
194 	/// \returns Y coordinate of the rect corner
195 	///
196 	////////////////////////////////////////////////////////////
GetY() const197 	constexpr int GetY() const {
198 		return y;
199 	}
200 
201 	////////////////////////////////////////////////////////////
202 	/// \brief Set Y coordinate of the rect corner
203 	///
204 	/// \param[in] ny New Y coordinate value
205 	///
206 	/// \returns Reference to self
207 	///
208 	////////////////////////////////////////////////////////////
SetY(int ny)209 	Rect& SetY(int ny) {
210 		y = ny;
211 		return *this;
212 	}
213 
214 	////////////////////////////////////////////////////////////
215 	/// \brief Get width of the rect
216 	///
217 	/// \returns Width of the rect
218 	///
219 	////////////////////////////////////////////////////////////
GetW() const220 	constexpr int GetW() const {
221 		return w;
222 	}
223 
224 	////////////////////////////////////////////////////////////
225 	/// \brief Set width of the rect
226 	///
227 	/// \param[in] nw New width of the rect
228 	///
229 	/// \returns Reference to self
230 	///
231 	////////////////////////////////////////////////////////////
SetW(int nw)232 	Rect& SetW(int nw) {
233 		w = nw;
234 		return *this;
235 	}
236 
237 	////////////////////////////////////////////////////////////
238 	/// \brief Get height of the rect
239 	///
240 	/// \returns Height of the rect
241 	///
242 	////////////////////////////////////////////////////////////
GetH() const243 	constexpr int GetH() const {
244 		return h;
245 	}
246 
247 	////////////////////////////////////////////////////////////
248 	/// \brief Set height of the rect
249 	///
250 	/// \param[in] nh New height of the rect
251 	///
252 	/// \returns Reference to self
253 	///
254 	////////////////////////////////////////////////////////////
SetH(int nh)255 	Rect& SetH(int nh) {
256 		h = nh;
257 		return *this;
258 	}
259 
260 	////////////////////////////////////////////////////////////
261 	/// \brief Get X coordinate of the rect second corner
262 	///
263 	/// \returns X coordinate of the rect second corner
264 	///
265 	////////////////////////////////////////////////////////////
GetX2() const266 	constexpr int GetX2() const {
267 		return x + w - 1;
268 	}
269 
270 	////////////////////////////////////////////////////////////
271 	/// \brief Set X coordinate of the rect second corner
272 	///
273 	/// \param[in] x2 New X coordinate value
274 	///
275 	/// This modifies rectangle width internally
276 	///
277 	/// \returns Reference to self
278 	///
279 	////////////////////////////////////////////////////////////
SetX2(int x2)280 	Rect& SetX2(int x2) {
281 		w = x2 - x + 1;
282 		return *this;
283 	}
284 
285 	////////////////////////////////////////////////////////////
286 	/// \brief Get Y coordinate of the rect second corner
287 	///
288 	/// \returns Y coordinate of the rect second corner
289 	///
290 	////////////////////////////////////////////////////////////
GetY2() const291 	constexpr int GetY2() const {
292 		return y + h - 1;
293 	}
294 
295 	////////////////////////////////////////////////////////////
296 	/// \brief Set Y coordinate of the rect second corner
297 	///
298 	/// \param[in] y2 New Y coordinate value
299 	///
300 	/// This modifies rectangle height internally
301 	///
302 	/// \returns Reference to self
303 	///
304 	////////////////////////////////////////////////////////////
SetY2(int y2)305 	Rect& SetY2(int y2) {
306 		h = y2 - y + 1;
307 		return *this;
308 	}
309 
310 	////////////////////////////////////////////////////////////
311 	/// \brief Get top left corner of the rect
312 	///
313 	/// \returns Top left corner of the rect
314 	///
315 	////////////////////////////////////////////////////////////
GetTopLeft() const316 	constexpr Point GetTopLeft() const {
317 		return Point(x, y);
318 	}
319 
320 	////////////////////////////////////////////////////////////
321 	/// \brief Get top right corner of the rect
322 	///
323 	/// \returns Top right corner of the rect
324 	///
325 	////////////////////////////////////////////////////////////
GetTopRight() const326 	constexpr Point GetTopRight() const {
327 		return Point(GetX2(), y);
328 	}
329 
330 	////////////////////////////////////////////////////////////
331 	/// \brief Get bottom left corner of the rect
332 	///
333 	/// \returns bottom left corner of the rect
334 	///
335 	////////////////////////////////////////////////////////////
GetBottomLeft() const336 	constexpr Point GetBottomLeft() const {
337 		return Point(x, GetY2());
338 	}
339 
340 	////////////////////////////////////////////////////////////
341 	/// \brief Get bottom right corner of the rect
342 	///
343 	/// \returns Bottom right corner of the rect
344 	///
345 	////////////////////////////////////////////////////////////
GetBottomRight() const346 	constexpr Point GetBottomRight() const {
347 		return Point(GetX2(), GetY2());
348 	}
349 
350 	////////////////////////////////////////////////////////////
351 	/// \brief Get size of the rect
352 	///
353 	/// \returns Size of the rect
354 	///
355 	////////////////////////////////////////////////////////////
GetSize() const356 	constexpr Point GetSize() const {
357 		return Point(w, h);
358 	}
359 
360 	////////////////////////////////////////////////////////////
361 	/// \brief Get centroid of the rect
362 	///
363 	/// \returns Centroid of the rect
364 	///
365 	////////////////////////////////////////////////////////////
GetCentroid() const366 	constexpr Point GetCentroid() const {
367 		return Point(x + w/2, y + h/2);
368 	}
369 
370 	////////////////////////////////////////////////////////////
371 	/// \brief Check whether the rect contains given point
372 	///
373 	/// \param[in] px X coordinate of a point
374 	/// \param[in] py Y coordinate of a point
375 	///
376 	/// \returns True if the point is contained in the rect
377 	///
378 	////////////////////////////////////////////////////////////
Contains(int px,int py) const379 	constexpr bool Contains(int px, int py) const {
380 		return px >= x && py >= y && px <= GetX2() && py <= GetY2();
381 	}
382 
383 	////////////////////////////////////////////////////////////
384 	/// \brief Check whether the rect contains given point
385 	///
386 	/// \param[in] point Point to check
387 	///
388 	/// \returns True if the point is contained in the rect
389 	///
390 	////////////////////////////////////////////////////////////
Contains(const Point & point) const391 	constexpr bool Contains(const Point& point) const {
392 		return point.x >= x && point.y >= y && point.x <= GetX2() && point.y <= GetY2();
393 	}
394 
395 	////////////////////////////////////////////////////////////
396 	/// \brief Check whether the rect contains another rect
397 	///
398 	/// \param[in] rect Rect to check
399 	///
400 	/// \returns True if the checked rect is contained in this rect
401 	///
402 	////////////////////////////////////////////////////////////
Contains(const Rect & rect) const403 	constexpr bool Contains(const Rect& rect) const {
404 		return rect.x >= x && rect.y >= y && rect.GetX2() <= GetX2() && rect.GetY2() <= GetY2();
405 	}
406 
407 	////////////////////////////////////////////////////////////
408 	/// \brief Check whether the rect intersects another rect
409 	///
410 	/// \param[in] rect Rect to check
411 	///
412 	/// \returns True if rectangles intersect
413 	///
414 	////////////////////////////////////////////////////////////
Intersects(const Rect & rect) const415 	constexpr bool Intersects(const Rect& rect) const {
416 		return !(rect.GetX2() < x || rect.GetY2() < y || rect.x > GetX2() || rect.y > GetY2());
417 	}
418 
419 	////////////////////////////////////////////////////////////
420 	/// \brief Calculate union with another rect
421 	///
422 	/// \param[in] rect Rect to union with
423 	///
424 	/// \returns Rect representing union of two rectangles
425 	///
426 	////////////////////////////////////////////////////////////
427 	Rect GetUnion(const Rect& rect) const;
428 
429 	////////////////////////////////////////////////////////////
430 	/// \brief Union rect with another rect
431 	///
432 	/// \param[in] rect Rect to union with
433 	///
434 	/// \returns Reference to self
435 	///
436 	////////////////////////////////////////////////////////////
437 	Rect& Union(const Rect& rect);
438 
439 	////////////////////////////////////////////////////////////
440 	/// \brief Get a rect extended by specified amount of pixels
441 	///
442 	/// \param[in] amount Number of pixels to extend by
443 	///
444 	/// \returns Extended rect
445 	///
446 	////////////////////////////////////////////////////////////
447 	Rect GetExtension(unsigned int amount) const;
448 
449 	////////////////////////////////////////////////////////////
450 	/// \brief Get a rect extended by specified amount of pixels
451 	///
452 	/// \param[in] hamount Number of pixels to extend by
453 	///                    in horizontal direction
454 	/// \param[in] vamount Number of pixels to extend by
455 	///                    in vertical direction
456 	///
457 	/// \returns Extended rect
458 	///
459 	////////////////////////////////////////////////////////////
460 	Rect GetExtension(unsigned int hamount, unsigned int vamount) const;
461 
462 	////////////////////////////////////////////////////////////
463 	/// \brief Extend a rect by specified amount of pixels
464 	///
465 	/// \param[in] amount Number of pixels to extend by
466 	///
467 	/// \returns Reference to self
468 	///
469 	////////////////////////////////////////////////////////////
470 	Rect& Extend(unsigned int amount);
471 
472 	////////////////////////////////////////////////////////////
473 	/// \brief Extend a rect by specified amount of pixels
474 	///
475 	/// \param[in] hamount Number of pixels to extend by
476 	///                    in horizontal direction
477 	/// \param[in] vamount Number of pixels to extend by
478 	///                    in vertical direction
479 	///
480 	/// \returns Reference to self
481 	///
482 	////////////////////////////////////////////////////////////
483 	Rect& Extend(unsigned int hamount, unsigned int vamount);
484 
485 	////////////////////////////////////////////////////////////
486 	/// \brief Calculate intersection with another rect
487 	///
488 	/// \param[in] rect Rect to intersect with
489 	///
490 	/// \returns Rect representing intersection area or NullOpt if there was no intersection
491 	///
492 	////////////////////////////////////////////////////////////
493 	Optional<Rect> GetIntersection(const Rect& rect) const;
494 
495 	////////////////////////////////////////////////////////////
496 	/// \brief Calculate the intersection of a rectangle and line segment
497 	///
498 	/// \param[in,out] x1 Starting X-coordinate of the line
499 	/// \param[in,out] y1 Starting Y-coordinate of the line
500 	/// \param[in,out] x2 Ending X-coordinate of the line
501 	/// \param[in,out] y2 Ending Y-coordinate of the line
502 	///
503 	/// \returns True if there is an intersection, false otherwise
504 	///
505 	/// This function is used to clip a line segment to a
506 	/// rectangle. A line segment contained entirely within the
507 	/// rectangle or that does not intersect will remain unchanged.
508 	/// A line segment that crosses the rectangle at either or both
509 	/// ends will be clipped to the boundary of the rectangle and
510 	/// the new coordinates saved in x1, y1, x2, and/or y2 as
511 	/// necessary.
512 	///
513 	////////////////////////////////////////////////////////////
514 	bool IntersectLine(int& x1, int& y1, int& x2, int& y2) const;
515 
516 	////////////////////////////////////////////////////////////
517 	/// \brief Calculate the intersection of a rectangle and line segment
518 	///
519 	/// \param[in,out] p1 Starting coordinates of the line
520 	/// \param[in,out] p2 Ending coordinates of the line
521 	///
522 	/// \returns True if there is an intersection, false otherwise
523 	///
524 	/// This function is used to clip a line segment to a
525 	/// rectangle. A line segment contained entirely within the
526 	/// rectangle or that does not intersect will remain unchanged.
527 	/// A line segment that crosses the rectangle at either or both
528 	/// ends will be clipped to the boundary of the rectangle and
529 	/// the new coordinates saved in p1 and/or p2 as necessary.
530 	///
531 	////////////////////////////////////////////////////////////
532 	bool IntersectLine(Point& p1, Point& p2) const;
533 
534 	////////////////////////////////////////////////////////////
535 	/// \brief Get rectangle moved by a given offset
536 	///
537 	/// \param[in] offset Point specifying an offset
538 	///
539 	/// \returns Moved rectangle
540 	///
541 	////////////////////////////////////////////////////////////
operator +(const Point & offset) const542 	constexpr Rect operator+(const Point& offset) const {
543 		return Rect(x + offset.x, y + offset.y, w, h);
544 	}
545 
546 	////////////////////////////////////////////////////////////
547 	/// \brief Get rectangle moved by an opposite of given offset
548 	///
549 	/// \param[in] offset Point specifying an offset
550 	///
551 	/// \returns Moved rectangle
552 	///
553 	////////////////////////////////////////////////////////////
operator -(const Point & offset) const554 	constexpr Rect operator-(const Point& offset) const {
555 		return Rect(x - offset.x, y - offset.y, w, h);
556 	}
557 
558 	////////////////////////////////////////////////////////////
559 	/// \brief Move by then given offset
560 	///
561 	/// \param[in] offset Point specifying an offset
562 	///
563 	/// \returns Reference to self
564 	///
565 	////////////////////////////////////////////////////////////
operator +=(const Point & offset)566 	Rect& operator+=(const Point& offset) {
567 		x += offset.x;
568 		y += offset.y;
569 		return *this;
570 	}
571 
572 	////////////////////////////////////////////////////////////
573 	/// \brief Move by an opposite of the given offset
574 	///
575 	/// \param[in] offset Point specifying an offset
576 	///
577 	/// \returns Reference to self
578 	///
579 	////////////////////////////////////////////////////////////
operator -=(const Point & offset)580 	Rect& operator-=(const Point& offset) {
581 		x -= offset.x;
582 		y -= offset.y;
583 		return *this;
584 	}
585 };
586 
587 }
588 
589 ////////////////////////////////////////////////////////////
590 /// \brief Equality operator for SDL2pp::Rect
591 ///
592 /// \param[in] a First argument for comparison
593 /// \param[in] b Second argument for comparison
594 ///
595 /// \returns True if two rectangles are identical
596 ///
597 ////////////////////////////////////////////////////////////
operator ==(const SDL2pp::Rect & a,const SDL2pp::Rect & b)598 constexpr bool operator==(const SDL2pp::Rect& a, const SDL2pp::Rect& b) {
599 	return a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h;
600 }
601 
602 ////////////////////////////////////////////////////////////
603 /// \brief Inequality operator for SDL2pp::Rect
604 ///
605 /// \param[in] a First argument for comparison
606 /// \param[in] b Second argument for comparison
607 ///
608 /// \returns True if two rectangles are not identical
609 ///
610 ////////////////////////////////////////////////////////////
operator !=(const SDL2pp::Rect & a,const SDL2pp::Rect & b)611 constexpr bool operator!=(const SDL2pp::Rect& a, const SDL2pp::Rect& b) {
612 	return !(a == b);
613 }
614 
615 ////////////////////////////////////////////////////////////
616 /// \brief Less-than operator for SDL2pp::Rect
617 ///
618 /// \param[in] a First argument for comparison
619 /// \param[in] b Second argument for comparison
620 ///
621 /// \returns True if a < b
622 ///
623 ////////////////////////////////////////////////////////////
624 SDL2PP_EXPORT bool operator<(const SDL2pp::Rect& a, const SDL2pp::Rect& b);
625 
626 ////////////////////////////////////////////////////////////
627 /// \brief Stream output operator overload for SDL2pp::Rect
628 ///
629 /// \param[in] stream Stream to output to
630 /// \param[in] rect Rect to output
631 ///
632 /// \returns stream
633 ///
634 ////////////////////////////////////////////////////////////
635 SDL2PP_EXPORT std::ostream& operator<<(std::ostream& stream, const SDL2pp::Rect& rect);
636 
637 namespace std {
638 
639 ////////////////////////////////////////////////////////////
640 /// \brief std::hash specialization for SDL2pp::Rect
641 ///
642 ////////////////////////////////////////////////////////////
643 template<>
644 struct hash<SDL2pp::Rect> {
645 	////////////////////////////////////////////////////////////
646 	/// \brief Hash function for SDL2pp::Rect
647 	///
648 	/// \param[in] r Input Rect
649 	///
650 	/// \returns Hash value
651 	///
652 	////////////////////////////////////////////////////////////
operator ()std::hash653 	size_t operator()(const SDL2pp::Rect& r) const {
654 		size_t seed = std::hash<int>()(r.x);
655 		seed ^= std::hash<int>()(r.y) + 0x9e3779b9 + (seed<<6) + (seed>>2);
656 		seed ^= std::hash<int>()(r.w) + 0x9e3779b9 + (seed<<6) + (seed>>2);
657 		seed ^= std::hash<int>()(r.h) + 0x9e3779b9 + (seed<<6) + (seed>>2);
658 		return seed;
659 	}
660 };
661 
662 }
663 
664 #endif
665