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