Gamedev Framework (gf)  0.6.0
A C++11 framework for 2D games
Transform.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2017 Julien Bernard
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 #ifndef GF_TRANSFORM_H
22 #define GF_TRANSFORM_H
23 
24 #include <cmath>
25 
26 #include "Matrix.h"
27 #include "Portability.h"
28 #include "Rect.h"
29 #include "Vector.h"
30 
31 namespace gf {
32 #ifndef DOXYGEN_SHOULD_SKIP_THIS
33 inline namespace v1 {
34 #endif
35 
36  /**
37  * @brief A rotation
38  *
39  * @sa gf::Translation, gf::Transform
40  */
41  struct GF_API Rotation {
42  float cos; ///< The cosine of the rotation angle
43  float sin; ///< The sine of the rotation angle
44 
45  /**
46  * @brief Default constructor
47  *
48  * The default rotation is a rotation of angle @f$ 0 @f$.
49  */
51  : cos(1.0f), sin(0.0f)
52  {
53 
54  }
55 
56  /**
57  * @brief Constructor with an angle
58  *
59  * @param angle The rotation angle
60  */
61  Rotation(float angle)
62  : cos(std::cos(angle)), sin(std::sin(angle))
63  {
64 
65  }
66 
67  /**
68  * @brief Set the rotation angle
69  *
70  * @param angle The new rotation angle
71  */
72  void setAngle(float angle) {
73  cos = std::cos(angle);
74  sin = std::sin(angle);
75  }
76 
77  /**
78  * @brief Get the rotation angle
79  *
80  * @returns The current rotation angle
81  */
82  float getAngle() const {
83  return std::atan2(sin, cos);
84  }
85  };
86 
87  /**
88  * @relates Rotation
89  * @brief Apply a rotation to a 2D point.
90  *
91  * @param rotation The rotation
92  * @param point The point to transform
93  * @return The transformed point
94  */
95  constexpr
96  Vector2f transform(const Rotation& rotation, Vector2f point) {
97  return {
98  rotation.cos * point.x - rotation.sin * point.y,
99  rotation.sin * point.x + rotation.cos * point.y
100  };
101  }
102 
103  /**
104  * @relates Rotation
105  * @brief Apply an inverse rotation to a 2D point.
106  *
107  * @param rotation The rotation
108  * @param point The point to transform
109  * @return The transformed point
110  */
111  constexpr
112  Vector2f inverseTransform(const Rotation& rotation, Vector2f point) {
113  return {
114  rotation.cos * point.x + rotation.sin * point.y,
115  -rotation.sin * point.x + rotation.cos * point.y
116  };
117  }
118 
119  /**
120  * @brief A translation
121  *
122  * @sa gf::Rotation, gf::Transform
123  */
125  Vector2f offset; ///< The offset of the translation
126 
127  /**
128  * @brief Default constructor
129  *
130  * The default translation has a null offset
131  */
133  : offset(0.0f, 0.0f)
134  {
135 
136  }
137 
138  /**
139  * @brief Constructor with an offset
140  *
141  * @param translationOffset The translation offset
142  */
143  Translation(Vector2f translationOffset)
145  {
146 
147  }
148 
149  /**
150  * @brief Set the translation offset
151  *
152  * @param newOffset The new offset
153  */
154  void setOffset(Vector2f newOffset) noexcept {
155  offset = newOffset;
156  }
157 
158  /**
159  * @brief Get the translation offset
160  *
161  * @return The current translation offset
162  */
163  Vector2f getOffset() const noexcept {
164  return offset;
165  }
166  };
167 
168  /**
169  * @relates Translation
170  * @brief Apply a translation to a 2D point.
171  *
172  * @param translation The translation
173  * @param point The point to transform
174  * @return The transformed point
175  */
176  constexpr
177  Vector2f transform(const Translation& translation, Vector2f point) {
178  return { point.x + translation.offset.x, point.y + translation.offset.y };
179  }
180 
181  /**
182  * @relates Translation
183  * @brief Apply an inverse translation to a 2D point.
184  *
185  * @param translation The translation
186  * @param point The point to transform
187  * @return The transformed point
188  */
189  constexpr
190  Vector2f inverseTransform(const Translation& translation, Vector2f point) {
191  return { point.x - translation.offset.x, point.y - translation.offset.y };
192  }
193 
194  /**
195  * @brief A simple transformation (rotation then translation)
196  *
197  * This class is meant for simple transformation as can be seen in physics.
198  * It is the composition of a rotation and a translation.
199  *
200  * For more complex affine transformation, you can use gf::Matrix3f.
201  *
202  * @sa gf::Matrix3f, gf::Rotation, gf::Translation
203  */
204  struct GF_API Transform {
205  Rotation rotation; ///< The rotation of the transformation
206  Translation translation; ///< The translation of the transformation
207 
208  /**
209  * @brief Default constructor
210  *
211  * The default transform is the identity.
212  */
214  {
215 
216  }
217 
218  /**
219  * @brief Constructor with a rotation and a translation
220  *
221  * @param angle The rotation angle
222  * @param offset The translation offset
223  */
224  Transform(float angle, Vector2f offset)
225  : rotation(angle), translation(offset)
226  {
227 
228  }
229 
230  /**
231  * @brief Constructor with a rotation
232  *
233  * There is no translation.
234  *
235  * @param angle The rotation angle
236  */
237  Transform(float angle)
238  : rotation(angle)
239  {
240 
241  }
242 
243  /**
244  * @brief Constructor with a translation
245  *
246  * There is no rotation.
247  *
248  * @param offset The translation offset
249  */
250  Transform(Vector2f offset)
252  {
253 
254  }
255 
256  /**
257  * @brief Set the rotation angle
258  *
259  * @param angle The rotation angle
260  */
261  void setAngle(float angle) {
262  rotation.setAngle(angle);
263  }
264 
265  /**
266  * @brief Get the rotation angle
267  *
268  * @returns The rotation angle
269  */
270  float getAngle() const {
271  return rotation.getAngle();
272  }
273 
274  /**
275  * @brief Set the translation offset
276  *
277  * @param offset The translation offset
278  */
279  void setOffset(Vector2f offset) noexcept {
280  translation.setOffset(offset);
281  }
282 
283  /**
284  * @brief Get the translation offset
285  *
286  * @returns The translation offset
287  */
288  Vector2f getOffset() const noexcept {
289  return translation.getOffset();
290  }
291 
292  };
293 
294  /**
295  * @relates Transform
296  * @brief Apply a transformation to a 2D point.
297  *
298  * @param trans The transformation
299  * @param point The point to transform
300  * @return The transformed point
301  */
302  constexpr
303  Vector2f transform(const Transform& trans, Vector2f point) {
304  return transform(trans.translation, transform(trans.rotation, point));
305  }
306 
307  /**
308  * @relates Transform
309  * @brief Apply an inverse transformation to a 2D point.
310  *
311  * @param trans The transformation
312  * @param point The point to transform
313  * @return The transformed point
314  */
315  constexpr
316  Vector2f inverseTransform(const Transform& trans, Vector2f point) {
317  return inverseTransform(trans.rotation, inverseTransform(trans.translation, point));
318  }
319 
320  // https://en.wikipedia.org/wiki/Homogeneous_coordinates
321 
322  /**
323  * @ingroup core
324  * @brief Apply an affine transformation to a 2D point.
325  *
326  * @param mat The transformation matrix
327  * @param point The point to transform
328  * @return The transformed point
329  */
330  constexpr
331  Vector2f transform(const Matrix3f& mat, Vector2f point) {
332  return { mat.xx * point.x + mat.xy * point.y + mat.xz, mat.yx * point.x + mat.yy * point.y + mat.yz };
333  }
334 
335  /**
336  * @ingroup core
337  * @brief Apply an affine transformaton to a rectangle
338  *
339  * The resulting rectangle is axis-aligned
340  *
341  * @param mat The transformation matrix
342  * @param rect The rectangle to transform
343  * @return The transformed rectangle
344  */
345  GF_API RectF transform(const Matrix3f& mat, const RectF& rect);
346 
347 
348  /**
349  * @ingroup core
350  * @brief Identity transform
351  *
352  * @return The identity matrix
353  */
354  constexpr Matrix3f identityTransform() {
355  return Matrix3f(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
356  }
357 
358  /**
359  * @ingroup core
360  * @brief Get a translation matrix
361  *
362  * @param offset The offset of the translation
363  * @return A translation by `offset`
364  */
365  inline
366  Matrix3f translation(Vector2f offset) {
367  return Matrix3f{
368  1.0f, 0.0f, offset.x,
369  0.0f, 1.0f, offset.y,
370  0.0f, 0.0f, 1.0f
371  };
372  }
373 
374  /**
375  * @ingroup core
376  * @brief Combine the current transform with a translation
377  *
378  * @param mat The current transform
379  * @param offset The offset of the translation
380  */
381  GF_API void translate(Matrix3f& mat, Vector2f offset);
382 
383  /**
384  * @ingroup core
385  * @brief Get a rotation matrix
386  *
387  * @param angle The angle of the rotation (in radians)
388  * @return A rotation of `angle` radians
389  */
390  inline
391  Matrix3f rotation(float angle) {
392  float cos = std::cos(angle);
393  float sin = std::sin(angle);
394  return Matrix3f{
395  cos, -sin, 0.0f,
396  sin, cos, 0.0f,
397  0.0f, 0.0f, 1.0f
398  };
399  }
400 
401  /**
402  * @ingroup core
403  * @brief Get a rotation matrix
404  *
405  * @param angle The angle of the rotation (in radians)
406  * @param center The center of the rotation
407  * @return A rotation of `angle` radians of origin `center`
408  */
409  inline
410  Matrix3f rotation(float angle, Vector2f center) {
411  float cos = std::cos(angle);
412  float sin = std::sin(angle);
413  return Matrix3f{
414  cos, -sin, center.x * (1 - cos) + center.y * sin,
415  sin, cos, center.y * (1 - cos) - center.x * sin,
416  0.0f, 0.0f, 1.0f
417  };
418  }
419 
420  /**
421  * @ingroup core
422  * @brief Combine the current transform with a rotation
423  *
424  * @param mat The current transform
425  * @param angle The angle of the rotation (in radians)
426  */
427  GF_API void rotate(Matrix3f& mat, float angle);
428 
429  /**
430  * @ingroup core
431  * @brief Combine the current transform with a rotation
432  *
433  * @param mat The current transform
434  * @param angle The angle of the rotation (in radians)
435  * @param center The center of the rotation
436  */
437  GF_API void rotate(Matrix3f& mat, float angle, Vector2f center);
438 
439  /**
440  * @ingroup core
441  * @brief Get a scaling matrix
442  *
443  * @param factor The scaling factor
444  * @return A scaling by `factor`
445  */
446  inline
447  Matrix3f scaling(Vector2f factor) {
448  return Matrix3f{
449  factor.x, 0.0f, 0.0f,
450  0.0f, factor.y, 0.0f,
451  0.0f, 0.0f, 1.0f
452  };
453  }
454 
455  /**
456  * @ingroup core
457  * @brief Get a scaling matrix
458  *
459  * @param factor The scaling factor
460  * @param center The center of the scaling
461  * @return A scaling by `factor` of origin `center`
462  */
463  inline
464  Matrix3f scaling(Vector2f factor, Vector2f center) {
465  return Matrix3f{
466  factor.x, 0.0f, center.x * (1.0f - factor.x),
467  0.0f, factor.y, center.y * (1.0f - factor.y),
468  0.0f, 0.0f, 1.0f
469  };
470  }
471 
472  /**
473  * @ingroup core
474  * @brief Combine the current transform with a scaling
475  *
476  * @param mat The current transform
477  * @param factor The scaling factor
478  */
479  GF_API void scale(Matrix3f& mat, Vector2f factor);
480 
481  /**
482  * @ingroup core
483  * @brief Combine the current transform with a scaling
484  *
485  * @param mat The current transform
486  * @param factor The scaling factor
487  * @param center The center of the scaling
488  */
489  GF_API void scale(Matrix3f& mat, Vector2f factor, Vector2f center);
490 
491 #ifndef DOXYGEN_SHOULD_SKIP_THIS
492 }
493 #endif
494 }
495 
496 #endif // GF_TRANSFORM_H
constexpr Vector2f inverseTransform(const Translation &translation, Vector2f point)
Apply an inverse translation to a 2D point.
Definition: Transform.h:190
Vector2f getOffset() const noexcept
Get the translation offset.
Definition: Transform.h:288
Rotation(float angle)
Constructor with an angle.
Definition: Transform.h:61
constexpr Vector2f inverseTransform(const Transform &trans, Vector2f point)
Apply an inverse transformation to a 2D point.
Definition: Transform.h:316
void scale(Matrix3f &mat, Vector2f factor)
Combine the current transform with a scaling.
void setOffset(Vector2f newOffset) noexcept
Set the translation offset.
Definition: Transform.h:154
float getAngle() const
Get the rotation angle.
Definition: Transform.h:82
constexpr Vector2f transform(const Matrix3f &mat, Vector2f point)
Apply an affine transformation to a 2D point.
Definition: Transform.h:331
Vector2f offset
The offset of the translation.
Definition: Transform.h:125
Rotation rotation
The rotation of the transformation.
Definition: Transform.h:205
Matrix3f rotation(float angle, Vector2f center)
Get a rotation matrix.
Definition: Transform.h:410
Transform(float angle)
Constructor with a rotation.
Definition: Transform.h:237
Matrix3f scaling(Vector2f factor)
Get a scaling matrix.
Definition: Transform.h:447
void setOffset(Vector2f offset) noexcept
Set the translation offset.
Definition: Transform.h:279
A simple transformation (rotation then translation)
Definition: Transform.h:204
constexpr Vector2f transform(const Rotation &rotation, Vector2f point)
Apply a rotation to a 2D point.
Definition: Transform.h:96
float sin
The sine of the rotation angle.
Definition: Transform.h:43
A translation.
Definition: Transform.h:124
Matrix3f scaling(Vector2f factor, Vector2f center)
Get a scaling matrix.
Definition: Transform.h:464
Translation translation
The translation of the transformation.
Definition: Transform.h:206
constexpr Vector2f transform(const Translation &translation, Vector2f point)
Apply a translation to a 2D point.
Definition: Transform.h:177
Translation()
Default constructor.
Definition: Transform.h:132
void scale(Matrix3f &mat, Vector2f factor, Vector2f center)
Combine the current transform with a scaling.
Vector2f getOffset() const noexcept
Get the translation offset.
Definition: Transform.h:163
Transform(float angle, Vector2f offset)
Constructor with a rotation and a translation.
Definition: Transform.h:224
Translation(Vector2f translationOffset)
Constructor with an offset.
Definition: Transform.h:143
The namespace for gf classes.
Definition: Action.h:34
Matrix3f rotation(float angle)
Get a rotation matrix.
Definition: Transform.h:391
Transform(Vector2f offset)
Constructor with a translation.
Definition: Transform.h:250
float getAngle() const
Get the rotation angle.
Definition: Transform.h:270
void rotate(Matrix3f &mat, float angle)
Combine the current transform with a rotation.
Matrix3f translation(Vector2f offset)
Get a translation matrix.
Definition: Transform.h:366
void translate(Matrix3f &mat, Vector2f offset)
Combine the current transform with a translation.
RectF transform(const Matrix3f &mat, const RectF &rect)
Apply an affine transformaton to a rectangle.
Transform()
Default constructor.
Definition: Transform.h:213
constexpr Vector2f inverseTransform(const Rotation &rotation, Vector2f point)
Apply an inverse rotation to a 2D point.
Definition: Transform.h:112
void setAngle(float angle)
Set the rotation angle.
Definition: Transform.h:72
A rotation.
Definition: Transform.h:41
void rotate(Matrix3f &mat, float angle, Vector2f center)
Combine the current transform with a rotation.
Rotation()
Default constructor.
Definition: Transform.h:50
#define GF_API
Definition: Portability.h:35
constexpr Vector2f transform(const Transform &trans, Vector2f point)
Apply a transformation to a 2D point.
Definition: Transform.h:303
constexpr Matrix3f identityTransform()
Identity transform.
Definition: Transform.h:354
void setAngle(float angle)
Set the rotation angle.
Definition: Transform.h:261
float cos
The cosine of the rotation angle.
Definition: Transform.h:42