ge211
ge211_geometry.h
1 #pragma once
2 
3 #include "ge211_forward.h"
4 #include "ge211_util.h"
5 #include <SDL_rect.h>
6 #include <type_traits>
7 
8 namespace ge211 {
9 
11 namespace geometry {
12 
17 template <class T>
18 struct Basic_dimensions
19 {
22  using Coordinate = T;
23 
26 
34  template <class U>
36  noexcept(is_nothrow_convertible<Coordinate, U>())
37  {
38  return {U(width), U(height)};
39  }
40 };
41 
45 
47 template <class T>
49  noexcept(is_nothrow_comparable<T>())
50 {
51  return a.width == b.width && a.height == b.height;
52 }
53 
55 template <class T>
57  noexcept(is_nothrow_comparable<T>())
58 {
59  return !(a == b);
60 }
61 
63 template<class T>
66  noexcept(has_nothrow_arithmetic<T>())
67 {
68  return {d1.width + d2.width, d1.height + d2.height};
69 }
70 
72 template <class T>
75  noexcept(has_nothrow_arithmetic<T>())
76 {
77  return {d1.width - d2.width, d1.height - d2.height};
78 }
79 
81 template <class T>
83  noexcept(has_nothrow_arithmetic<T>())
84 {
85  return {d1.width * s2, d1.height * s2};
86 }
87 
89 template <class T>
91  noexcept(has_nothrow_arithmetic<T>())
92 {
93  return d2 * s1;
94 }
95 
102 template <class T,
103  class = std::enable_if_t<!std::is_same<T, double>::value, void>>
105  noexcept(has_nothrow_arithmetic<T, double>())
106 {
107  return {static_cast<T>(d1.width * s2),
108  static_cast<T>(d1.height * s2)};
109 }
110 
117 template <class T,
118  class = std::enable_if_t<!std::is_same<T, double>::value, void>>
120  noexcept(has_nothrow_arithmetic<double, T>())
121 {
122  return d2 * s1;
123 }
124 
131 template <class T>
133  noexcept(has_nothrow_division<double, T>())
134 {
135  return {d1.width / s2, d1.height / s2};
136 }
137 
144 template <class T,
145  class = std::enable_if_t<!std::is_same<T, double>::value, void>>
147  noexcept(has_nothrow_arithmetic<T, double>)
148 {
149  return d1 * (1 / s2);
150 }
151 
153 template <class T>
156  noexcept(has_nothrow_arithmetic<T>)
157 {
158  return d1 = d1 + d2;
159 }
160 
162 template <class T>
165  noexcept(has_nothrow_arithmetic<T>)
166 {
167  return d1 = d1 - d2;
168 }
169 
171 template <class T>
174 {
175  return d1 = d1 * s2;
176 }
177 
179 template <class T>
181  noexcept(has_nothrow_arithmetic<T, double>)
182 {
183  return d1 = d1 * s2;
184 }
185 
190 template <class T>
192  noexcept(has_nothrow_division<T>)
193 {
194  return d1 = d1 / s2;
195 }
196 
198 template <class T>
200  noexcept(has_nothrow_division<T, double>)
201 {
202  return d1 = d1 / s2;
203 }
204 
210 template <class T>
211 struct Basic_position
212 {
215  using Coordinate = T;
219 
221  Coordinate y;
225 
228  noexcept(is_nothrow_convertible<Coordinate>())
229  : x{x}, y{y}
230  { }
231 
234  explicit Basic_position(Dimensions dims)
235  noexcept(is_nothrow_convertible<Coordinate>())
236  : Basic_position{dims.width, dims.height}
237  { }
238 
246  template <class U>
247  Basic_position<U> into() const
248  noexcept(is_nothrow_convertible<Coordinate, U>())
249  {
250  return {U(x), U(y)};
251  }
252 
254 
257 
261  noexcept(has_nothrow_arithmetic<Coordinate>())
262  {
263  return {x, y - dy};
264  }
265 
269  noexcept(has_nothrow_arithmetic<Coordinate>())
270  {
271  return {x, y + dy};
272  }
273 
277  noexcept(has_nothrow_arithmetic<Coordinate>())
278  {
279  return {x - dx, y};
280  }
281 
285  noexcept(has_nothrow_arithmetic<Coordinate>())
286  {
287  return {x + dx, y};
288  }
289 
293  noexcept(has_nothrow_arithmetic<Coordinate>())
294  {
295  return {x - dims.width, y - dims.height};
296  }
297 
301  noexcept(has_nothrow_arithmetic<Coordinate>())
302  {
303  return {x + dims.width, y - dims.height};
304  }
305 
309  noexcept(has_nothrow_arithmetic<Coordinate>())
310  {
311  return {x - dims.width, y + dims.height};
312  }
313 
317  noexcept(has_nothrow_arithmetic<Coordinate>())
318  {
319  return {x + dims.width, y + dims.height};
320  }
321 
323 };
324 
328 
330 template <class T>
332  noexcept(is_nothrow_comparable<T>())
333 {
334  return p1.x == p2.x && p1.y == p2.y;
335 }
336 
338 template <class T>
340  noexcept(is_nothrow_comparable<T>())
341 {
342  return !(p1 == p2);
343 }
344 
347 template <class T>
349  noexcept(has_nothrow_arithmetic<T>())
350 {
351  return p1.down_right_by(d2);
352 }
353 
355 template <class T>
357  noexcept(has_nothrow_arithmetic<T>())
358 {
359  return p2.down_right_by(d1);
360 }
361 
364 template <class T>
366  noexcept(has_nothrow_arithmetic<T>())
367 {
368  return p1.up_left_by(d2);
369 }
370 
372 template <class T>
374  noexcept(has_nothrow_arithmetic<T>())
375 {
376  return {p1.x - p2.x, p1.y - p2.y};
377 }
378 
380 template <class T>
382  noexcept(has_nothrow_arithmetic<T>())
383 {
384  return p1 = p1 + d2;
385 }
386 
388 template <class T>
390  noexcept(has_nothrow_arithmetic<T>())
391 {
392  return p1 = p1 - d2;
393 }
394 
396 template <class T>
397 struct Basic_rectangle
398 {
401  using Coordinate = T;
408 
410  Coordinate y;
415  template<typename U>
416  Basic_rectangle<U> into() const
417  noexcept(is_nothrow_convertible<Coordinate, U>)
418  {
419  return {U(x), U(y), U(width), U(height)};
420  }
421 
425  noexcept(has_nothrow_arithmetic<Coordinate>())
426  {
427  return {tl.x, tl.y, dims.width, dims.height};
428  }
429 
433  noexcept(has_nothrow_arithmetic<Coordinate>())
434  {
435  return from_top_left(tr.left_by(dims.width), dims);
436  }
437 
441  noexcept(has_nothrow_arithmetic<Coordinate>())
442  {
443  return from_top_left(bl.up_by(dims.height), dims);
444  }
445 
449  noexcept(has_nothrow_arithmetic<Coordinate>())
450  {
451  return from_top_left(br.up_left_by(dims), dims);
452  }
453 
457  noexcept(has_nothrow_arithmetic<Coordinate>())
458  {
459  return from_top_left(center.up_left_by(dims / Coordinate(2)), dims);
460  }
461 
464  Dimensions dimensions() const
466  {
467  return {width, height};
468  }
469 
471  Position top_left() const
473  {
474  return {x, y};
475  }
476 
478  Position top_right() const
480  {
481  return top_left().right_by(width);
482  }
483 
485  Position bottom_left() const
487  {
488  return top_left().down_by(height);
489  }
490 
492  Position bottom_right() const
494  {
495  return top_left().down_right_by(dimensions());
496  }
497 
499  Position center() const
500  noexcept(has_nothrow_arithmetic<Coordinate>() &&
502  {
503  return top_left().down_right_by(dimensions() / Coordinate(2));
504  }
505 
506  class iterator;
507 
509  iterator begin() const
510  {
511  return {top_left(), y, y + height};
512  }
513 
515  iterator end() const
516  {
517  return {top_left().right_by(width), y, y + height};
518  }
519 
520 private:
521  friend Circle_sprite;
522  friend detail::Render_sprite;
523  friend detail::Renderer;
524 
526  operator SDL_Rect() const
527  noexcept(is_nothrow_convertible<Coordinate, int>())
528  {
529  SDL_Rect result;
530  result.x = static_cast<int>(x);
531  result.y = static_cast<int>(y);
532  result.w = static_cast<int>(width);
533  result.h = static_cast<int>(height);
534  return result;
535  }
536 };
537 
540 using Rectangle = Basic_rectangle<int>;
541 
544 template <class T>
545 bool operator==(const Basic_rectangle<T>& r1,
546  const Basic_rectangle<T>& r2)
547  noexcept(is_nothrow_comparable<T>())
548 {
549 return r1.x == r2.x &&
550  r1.y == r2.y &&
551  r1.width == r2.width &&
552  r1.height == r2.height;
553 }
554 
556 template <class T>
557 bool operator!=(const Basic_rectangle<T> &r1,
558  const Basic_rectangle<T> &r2)
559  noexcept(is_nothrow_comparable<T>())
560 {
561  return !(r1 == r2);
562 }
563 
567 template <class T>
568 class Basic_rectangle<T>::iterator
569  : public std::iterator<
570  std::input_iterator_tag,
571  typename Basic_rectangle<T>::Position const >
572 {
573 public:
574 
576  Position operator*() const
577  {
578  return current_;
579  }
580 
582  Position const* operator->() const
583  {
584  return &current_;
585  }
586 
588  iterator& operator++()
589  {
590  if (++current_.y >= y_end_) {
591  ++current_.x;
592  current_.y = y_begin_;
593  }
594 
595  return *this;
596  }
597 
599  iterator& operator--()
600  {
601  if (current_.y == y_begin_) {
602  current_.y = y_end_;
603  --current_.x;
604  }
605 
606  --current_.y;
607 
608  return *this;
609  }
610 
612  iterator operator++(int)
613  {
614  iterator result(*this);
615  ++*this;
616  return result;
617  }
618 
620  iterator operator--(int)
621  {
622  iterator result(*this);
623  --*this;
624  return result;
625  }
626 
629  bool operator==(iterator const& that) const
630  {
631  return **this == *that;
632  }
633 
635  bool operator!=(iterator const& that) const
636  {
637  return !(*this == that);
638  }
639 
640 private:
641  friend Basic_rectangle<T>;
642 
643  iterator(Position current, Coordinate y_begin, Coordinate y_end)
644  : current_(current)
645  , y_begin_(y_begin)
646  , y_end_(y_end)
647  { }
648 
649  Position current_;
650  Coordinate y_begin_;
651  Coordinate y_end_;
652 };
653 
680 class Transform
681 {
682 public:
685 
687  Transform() noexcept;
688 
691  static Transform rotation(double) noexcept;
692 
694  static Transform flip_h() noexcept;
695 
697  static Transform flip_v() noexcept;
698 
700  static Transform scale(double) noexcept;
701 
703  static Transform scale_x(double) noexcept;
704 
706  static Transform scale_y(double) noexcept;
707 
709 
712 
715  Transform& set_rotation(double) noexcept;
717  Transform& set_flip_h(bool) noexcept;
719  Transform& set_flip_v(bool) noexcept;
723  Transform& set_scale(double) noexcept;
727  Transform& set_scale_x(double) noexcept;
731  Transform& set_scale_y(double) noexcept;
732 
734 
737 
739  double get_rotation() const noexcept;
741  bool get_flip_h() const noexcept;
743  bool get_flip_v() const noexcept;
745  double get_scale_x() const noexcept;
747  double get_scale_y() const noexcept;
748 
750 
753 
758  bool is_identity() const noexcept;
759 
761  Transform operator*(const Transform&) const noexcept;
762 
767  Transform inverse() const noexcept;
768 
770 
771 private:
772  double rotation_;
773  double scale_x_;
774  double scale_y_;
775  bool flip_h_;
776  bool flip_v_;
777 };
778 
780 bool operator==(const Transform&, const Transform&) noexcept;
782 bool operator!=(const Transform&, const Transform&) noexcept;
783 
784 } // end namespace geometry.
785 
786 }
Position bottom_right() const noexcept(has_nothrow_arithmetic< Coordinate >())
The position of the bottom right vertex.
static Basic_rectangle from_top_left(Position tl, Dimensions dims) noexcept(has_nothrow_arithmetic< Coordinate >())
Creates a Basic_rectangle given the position of its top left vertex and its dimensions.
static Basic_rectangle from_bottom_left(Position bl, Dimensions dims) noexcept(has_nothrow_arithmetic< Coordinate >())
Creates a Basic_rectangle given the position of its bottom left vertex and its dimensions.
Transform & set_flip_h(bool) noexcept
Modifies this transform to determine whether to flip horizontally.
Coordinate width
The width of the rectangle in pixels.
static Transform flip_v() noexcept
Constructs a transform that flips the sprite vertically.
Transform & set_rotation(double) noexcept
Modifies this transform to have the given rotation, in degrees degrees.
Basic_dimensions< T > operator/(Basic_dimensions< T > d1, T s2) noexcept(has_nothrow_division< double, T >())
Divides a Basic_dimensions by a T.
Basic_position up_right_by(Dimensions dims) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is above and right of this position by the given dimensions.
bool operator!=(const Transform &t1, const Transform &t2) noexcept
Disequality for transforms.
An iterator over the Basic_position<T>s of a Basic_rectangle<T>.
Basic_dimensions< T > & operator/=(Basic_dimensions< T > &d1, T s2) noexcept(has_nothrow_division< T >)
Succinct Basic_dimensions-scalar division.
Basic_position< U > into() const noexcept(is_nothrow_convertible< Coordinate, U >())
Converts a Basic_position to another coordinate type.
Coordinate width
The width of the object.
Coordinate height
The height of the object.
Basic_dimensions< T > & operator-=(Basic_dimensions< T > &d1, Basic_dimensions< T > d2) noexcept(has_nothrow_arithmetic< T >)
Succinct Basic_dimensions subtraction.
constexpr bool has_nothrow_division()
Can types T and U be used for division without risk of an exception?
Definition: ge211_util.h:56
Basic_dimensions< U > into() const noexcept(is_nothrow_convertible< Coordinate, U >())
Converts a Basic_dimensions to another coordinate type.
constexpr bool has_nothrow_arithmetic()
Can types T and U be used for basic arithmetic (addition, subtraction, multiplication) without risk o...
Definition: ge211_util.h:47
The game engine namespace.
Definition: ge211.h:17
Position bottom_left() const noexcept(has_nothrow_arithmetic< Coordinate >())
The position of the bottom left vertex.
Basic_dimensions< Coordinate > Dimensions
A dimensions type having the same coordinate type as this position type.
T Coordinate
The coordinate type for the position.
double get_scale_x() const noexcept
Returns how much the sprite will be scaled horizontally.
Represents a positioned rectangle.
Definition: ge211_forward.h:75
static Transform rotation(double) noexcept
Constructs a rotating transform, given the rotation in degrees clockwise.
static Basic_rectangle from_top_right(Position tr, Dimensions dims) noexcept(has_nothrow_arithmetic< Coordinate >())
Creates a Basic_rectangle given the position of its top right vertex and its dimensions.
Basic_rectangle< int > Rectangle
Type alias for the most common use of Basic_rectangle, which is with a coordinate type of int...
Definition: ge211_forward.h:79
static Basic_rectangle from_bottom_right(Position br, Dimensions dims) noexcept(has_nothrow_arithmetic< Coordinate >())
Creates a Basic_rectangle given the position of its bottom right vertex and its dimensions.
Dimensions dimensions() const noexcept(is_nothrow_convertible< Coordinate >())
The dimensions of the rectangle.
Basic_position(Coordinate x, Coordinate y) noexcept(is_nothrow_convertible< Coordinate >())
Constructs a position from the given x and y coordinates.
Coordinate height
The height of the rectangle in pixels.
Coordinate x
The x coordinate.
Coordinate y
The y coordiante.
Basic_dimensions< T > operator-(Basic_dimensions< T > d1, Basic_dimensions< T > d2) noexcept(has_nothrow_arithmetic< T >())
Subtracts two Basic_dimensionses. This is vector subtraction.
Basic_position down_by(Coordinate dy) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is below this position by the given amount.
bool operator==(const Transform &t1, const Transform &t2) noexcept
Equality for transforms.
T Coordinate
The coordinate type for the dimensions.
bool get_flip_v() const noexcept
Returns whether the sprite will be flipped vertically.
Transform & set_flip_v(bool) noexcept
Modifies this transform to determine whether to flip vertically.
double get_scale_y() const noexcept
Returns how much the sprite will be scaled vertically.
static Transform scale_x(double) noexcept
Constructs a transform that scales the sprite in the x dimension.
Transform inverse() const noexcept
Returns the inverse of this transform.
iterator begin() const
Returns an iterator to the top left corner of this rectangle.
Transform & set_scale_x(double) noexcept
Modifies this transform to scale the sprite horizontally.
Position top_left() const noexcept(has_nothrow_arithmetic< Coordinate >())
The position of the top left vertex.
A Sprite that renders as a solid circle.
Transform & set_scale(double) noexcept
Modifies this transform to scale the sprite by the given amount in both dimensions.
Basic_dimensions< T > & operator*=(Basic_dimensions< T > &d1, T s2) noexcept(has_nothrow_arithmetic< T >)
Succinct Basic_dimensions-scalar multiplication.
Represents the dimensions of an object, or more generally, the displacement between two Basic_positio...
Definition: ge211_forward.h:73
Transform & set_scale_y(double) noexcept
Modifies this transform to scale the sprite vertically.
A position in the T-valued Cartesian plane.
Definition: ge211_forward.h:74
A rendering transform, which can scale, flip, and rotate.
Position center() const noexcept(has_nothrow_arithmetic< Coordinate >() &&has_nothrow_division< Coordinate, int >())
The position of the center of the rectangle.
Basic_position down_left_by(Dimensions dims) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is below and left of this position by the given dimensions.
T Coordinate
The coordinate type for the rectangle.
Basic_dimensions< T > operator*(Basic_dimensions< T > d1, T s2) noexcept(has_nothrow_arithmetic< T >())
Multiplies a Basic_dimensions by a scalar.
Basic_position right_by(Coordinate dx) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is to the right of this position by the given amount.
static Transform scale(double) noexcept
Constructs a transform that scales the sprite in both dimensions.
static Transform scale_y(double) noexcept
Constructs a transform that scales the sprite in the y dimension.
static Basic_rectangle from_center(Position center, Dimensions dims) noexcept(has_nothrow_arithmetic< Coordinate >())
Creates a Basic_rectangle given the position of its center and its dimensions.
Basic_position up_by(Coordinate dy) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is above this position by the given amount.
Coordinate y
The y coordinate of the upper-left vertex.
Basic_position down_right_by(Dimensions dims) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is below and right of this position by the given dimensions.
double get_rotation() const noexcept
Returns the rotation that will be applied to the sprite.
static Transform flip_h() noexcept
Constructs a transform that flips the sprite horizontally.
Basic_rectangle< U > into() const noexcept(is_nothrow_convertible< Coordinate, U >)
Converts a Basic_rectangle to another coordinate type.
Basic_position up_left_by(Dimensions dims) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is above and left of this position by the given dimensions.
Transform() noexcept
Constructs the identity transform, which has no effect.
bool is_identity() const noexcept
Is this transformation the identity transformation that does nothing? Because floating point is appro...
constexpr bool is_nothrow_comparable()
Can type T be compared to itself without risk of an exception?
Definition: ge211_util.h:38
Position top_right() const noexcept(has_nothrow_arithmetic< Coordinate >())
The position of the top right vertex.
constexpr bool is_nothrow_convertible()
Can type T be converted to type U without risk of an exception?
Definition: ge211_util.h:30
bool get_flip_h() const noexcept
Returns whether the sprite will be flipped horizontally.
Coordinate x
The x coordinate of the upper-left vertex.
Basic_dimensions< T > & operator+=(Basic_dimensions< T > &d1, Basic_dimensions< T > d2) noexcept(has_nothrow_arithmetic< T >)
Succinct Basic_dimensions addition.
Basic_position left_by(Coordinate dx) const noexcept(has_nothrow_arithmetic< Coordinate >())
Constructs the position that is to the left of this position by the given amount. ...
Basic_dimensions< T > operator+(Basic_dimensions< T > d1, Basic_dimensions< T > d2) noexcept(has_nothrow_arithmetic< T >())
Adds two Basic_dimensionses. This is vector addition.
iterator end() const
Returns an iterator one past the end of this rectangle.