# 2D Transformations

This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.

## Functions

void | t2d_move (...) |

void | t2d_rotate (...) |

void | t2d_scale (...) |

void | t2d_invfast (...) |

void | t2d_inverse (...) |

void | t2d_mult (...) |

void | t2d_vmult (...) |

void | t2d_vmultn (...) |

void | t2d_decompose (...) |

## Types and Constants

T2D | kIDENT |

Affine transformations are a type of mathematical operation that allows coordinate changes between different reference systems. For example in (Figure 1) **(a)** we construct a polygon expressing the coordinates of its vertices in a Cartesian system: [ (4,1), (2,5), (-3,5), (-4,2), (0, -3) ]. Now let's imagine that we want to draw several instances of our model on a plane, each with a different position, orientation and size (Figure 1) **(b)**. We would need to calculate the coordinates of the points of the polygon in the new locations, in order to correctly draw the lines that delimit them.

Vector Algebra gives us a powerful tool with which the relationship between two systems can be expressed using six real numbers (Figure 2). The first four values correspond to a 2x2 matrix with the coordinates of the vectors X=[1,0] and Y=[0,1] in the new reference system. This matrix integrates a possible rotation and scaling of the axes. The last two values indicate a displacement in the origin of coordinates. In (Formula 1) we have the mathematical development to transform the point [4.1] to a new base rotated 25° with respect to the origin and displaced 11 units on the X axis and -5 on the Y axis. Applying the same operation to all points, we would transform the object.

## 1. Elementary transformations

In principle, any combination of values [i.x, i.y, j.x, j.y, p.x, p.y] would provide a valid transformation, although if we do not choose them with certain criteria we will obtain aberrations that are not very useful in practice. The most used transformations in graphic and engineering applications are (Figure 3) (Figure 4) (Formula 2):

- Translation
**(a)**: Moves the origin of the object to another point. - Rotation
**(b)**: Rotates the object on the origin of its local system. - Scaling
**(c)**: Change the size. If*sx*< 1, reduce.*sx*> 1, increase.*sx*= 1, does not vary. In non-uniform scales,*sx*and*sy*have different values, which will produce a distortion in the aspect ratio. - Identity
**(d)**: It is the null transformation. When applied, the vectors remain unchanged.

## 2. Composition of transformations

It is possible to compose or accumulate transformations by matrix multiplication (Formula 3). The usual thing in 2d models will be to obtain the final location of an object from the elementary transformations translation, rotation and scaling. The accumulation is also useful for positioning elements in hierarchical structures, where the location of each object depends directly on that of its upper node (parent).

- Use t2d_movef to add a displacement to an existing transformation.
- Use t2d_rotatef to add a rotation.
- Use t2d_scalef to add a scaling.
- Use t2d_multf to add a transformation.
- Use t2d_vmultf to apply a transformation to a vector.
- Use t2d_vmultnf to apply a transformation to several vectors.
- Use kT2D_IDENTf to reference the identity transformation.

Matrix multiplication is not commutative, but the order in which the operations are applied will affect the final result. For example in (Figure 5) **(a)**, the origin has been moved and then applied a rotation. In (Figure 5) **(b)** it has been done on the contrary, first rotate and then move.

1 2 3 4 5 6 7 8 9 |
// (a) First move, then rotate T2Df t2d; t2d_movef(&t2d, kT2D_IDENTf, 11, 0); t2d_rotatef(&t2d, &t2d, kBMATH_PIf / 4); // (b) First rotate, then move T2Df t2d; t2d_rotatef(&t2d, kT2D_IDENTf, kBMATH_PIf / 4); t2d_movef(&t2d, &t2d, 11, 0); |

## 3. Decomposition and inverse

Any chain of translations, rotations, and scales defines an affine reference frame that can be expressed in terms of a single traslation, rotation, and scale (Figure 6). We can "undo" this transformation and return to the origin through the inverse transformation (Listing 2).

- Use t2d_decomposef to get the components of a transformation.
- Use t2d_inversef to get the inverse transformation.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
T2Df t2d, inv, inv2; V2Df pos, sc; real32_t a; // Transform sequence t2d_rotatef(&t2d, kT2D_IDENTf, kBMATH_PIf / 4); t2d_movef(&t2d, &t2d, 11, 0); t2d_movef(&t2d, &t2d, 10, - 10); t2d_rotatef(&t2d, &t2d, - kBMATH_PIf / 2); t2d_scalef(&t2d, &t2d, 1.5f, 1); // Transform components t2d_decomposef(&t2d, &pos, &a, &sc); // Transform inverse t2d_inversef(&inv, &t2d); // Inverse from components t2d_scalef(&inv2, kT2D_IDENTf, 1/sc.x, 1/sc.y); t2d_rotatef(&inv2, &inv2, -a); t2d_movef(&inv2, &inv2, -pos.x, -pos.y); // inv == inv2 ('inv' more numerical accurate) |

## kIDENT

const T2Df kT2D_IDENTf; const T2Dd kT2D_IDENTd; const T2D T2D::kIDENT;

Represents the identity transformation.

## t2d_move ()

Multiply a transformation by a translation `t2d = src * move(x,y)`

.

void t2d_movef(T2Df *dest, const T2Df *src, const real32_t x, const real32_t y); void t2d_moved(T2Dd *dest, const T2Dd *src, const real64_t x, const real64_t y); void T2D::move(T2D *dest, const T2D *src, const real x, const real y);

dest | Result transformation. |

src | Initial transformation. |

x | X coordinate of displacement. |

y | Y coordinate of displacement. |

**Remarks**

`dest`

and `src`

can point to the same matrix.

## t2d_rotate ()

Multiply a transformation by a rotation `dest = src * rotate(a)`

.

void t2d_rotatef(T2Df *dest, const T2Df *src, const real32_t a); void t2d_rotated(T2Dd *dest, const T2Dd *src, const real64_t a); void T2D::rotate(T2D *dest, const T2D *src, const real a);

dest | Result transformation. |

src | Initial transformation. |

a | Rotation angle in radians. Positive angles are those that rotate from the X axis to the Y axis. |

**Remarks**

`dest`

and `src`

can point to the same matrix.

## t2d_scale ()

Multiply a transformation by an scale `dest = src * scale(sx,sy)`

.

void t2d_scalef(T2Df *dest, const T2Df *src, const real32_t sx, const real32_t sy); void t2d_scaled(T2Dd *dest, const T2Dd *src, const real64_t sx, const real64_t sy); void T2D::scale(T2D *dest, const T2D *src, const real sx, const real sy);

dest | Result transformation. |

src | Initial transformation. |

sx | Scaling on the x axis. |

sy | Scaling on the y axis. |

**Remarks**

`dest`

and `src`

can point to the same matrix.

## t2d_invfast ()

Calculate the inverse transformation, assuming the input is orthogonal.

void t2d_invfastf(T2Df *dest, const T2Df *src); void t2d_invfastd(T2Dd *dest, const T2Dd *src); void T2D::invfast(T2D *dest, const T2D *src);

dest | Inverse transformation. |

src | Initial transformation. |

**Remarks**

The transformation will be orthogonal only if it contains rotations and translations, otherwise the result of applying it will be unpredictable. `dest`

and `src`

can point to the same matrix.

## t2d_inverse ()

Calculate the inverse transformation.

void t2d_inversef(T2Df *dest, const T2Df *src); void t2d_inversed(T2Dd *dest, const T2Dd *src); void T2D::inverse(T2D *dest, const T2D *src);

dest | Inverse transformation. |

src | Initial transformation. |

**Remarks**

`dest`

and `src`

can point to the same matrix.

## t2d_mult ()

Multiply two transformations `dest = src1 * src2`

.

void t2d_multf(T2Df *dest, const T2Df *src1, const T2Df *src2); void t2d_multd(T2Dd *dest, const T2Dd *src1, const T2Dd *src2); void T2D::mult(T2D *dest, const T2D *src1, const T2D *src2);

dest | Result transformation. |

src1 | First operating. |

src2 | Second operating. |

**Remarks**

`dest`

, `src1`

and `src2`

can point to the same matrix.

## t2d_vmult ()

Transform a vector `dest = t2d * src`

.

void t2d_vmultf(V2Df *dest, const T2Df *t2d, const V2Df *src); void t2d_vmultd(V2Dd *dest, const T2Dd *t2d, const V2Dd *src); void T2D::vmult(V2D *dest, const T2D *t2d, const V2D *src);

dest | Transformed vector. |

t2d | Transformation. |

src | Original vector. |

**Remarks**

`dest`

and `src`

can point to the same vector.

## t2d_vmultn ()

Transform a vector list `dest[i] = t2d * src[i]`

.

void t2d_vmultnf(V2Df *dest, const T2Df *t2d, const V2Df *src, const uint32_t n); void t2d_vmultnd(V2Dd *dest, const T2Dd *t2d, const V2Dd *src, const uint32_t n); void T2D::vmultn(V2D *dest, const T2D *t2d, const V2D *src, const uint32_t n);

dest | Transformed vector array. |

t2d | Transformation. |

src | Original vector array. |

n | Number of vectors in |

**Remarks**

`dest`

and `src`

can point to the same array.

## t2d_decompose ()

Gets the position, rotation, and scaling of a transformation.

void t2d_decomposef(const T2Df *t2d, V2Df *pos, real32_t *a, V2Df *sc); void t2d_decomposed(const T2Dd *t2d, V2Dd *pos, real64_t *a, V2Dd *sc); void T2D::decompose(const T2D *t2d, V2D *pos, real *a, V2D *sc);

t2d | Transformation. |

pos | Position. Can be |

a | Angle in radians (-π/2, π/2). Can be |

sc | Scaled. Can be |

**Remarks**

If the transformation is not made up of a sequence of translations, rotations, and scales, the result will not be valid.