# Source code for pymunk.transform

```import math
from typing import NamedTuple, Tuple, Union, cast, overload

from .vec2d import Vec2d

[docs]
class Transform(NamedTuple):
"""Type used for 2x3 affine transforms.

See wikipedia for details:
http://en.wikipedia.org/wiki/Affine_transformation

The properties map to the matrix in this way:

= = ==
a c tx
b d ty
0 0  1
= = ==

An instance can be created in this way:

>>> Transform(1,2,3,4,5,6)
Transform(a=1, b=2, c=3, d=4, tx=5, ty=6)

Or overriding only some of the values (on a identity matrix):

>>> Transform(b=3,ty=5)
Transform(a=1, b=3, c=0, d=1, tx=0, ty=5)

Or using one of the static methods like identity or translation (see each
method for details).

The Transform supports the matrix multiplicaiton operator (@) with a
Transform, Vec2d or tuple as second operand, which produces a transformed
Transform or Vec2d as result:

>>> Transform.scaling(2) @ Transform.scaling(3)
Transform(a=6, b=0, c=0, d=6, tx=0, ty=0)
>>> Transform.scaling(2) @ Vec2d(1, 2)
Vec2d(2, 4)

"""

a: float = 1
b: float = 0
c: float = 0
d: float = 1
tx: float = 0
ty: float = 0

def __matmul__(self, other: Tuple[float, float]) -> Vec2d:
...

def __matmul__(
self, other: Tuple[float, float, float, float, float, float]
) -> "Transform":
...

[docs]
def __matmul__(
self,
other: Union[
Tuple[float, float], Tuple[float, float, float, float, float, float]
],
) -> Union[Vec2d, "Transform"]:

"""Multiply this transform with a Transform, Vec2d or Tuple of size 2
or 6.

Examples (Transform @ Transform):

>>> Transform() @ Transform() == Transform.identity()
True
>>> Transform.translation(2,3) @ Transform.translation(4,5)
Transform(a=1, b=0, c=0, d=1, tx=6, ty=8)
>>> Transform.scaling(2) @ Transform.scaling(3)
Transform(a=6, b=0, c=0, d=6, tx=0, ty=0)
>>> Transform.scaling(2) @ Transform.translation(3,4)
Transform(a=2, b=0, c=0, d=2, tx=6, ty=8)
>>> Transform.translation(3,4) @ Transform.scaling(2)
Transform(a=2, b=0, c=0, d=2, tx=3, ty=4)

Examples (Transform @ Vec2d):

>>> Transform.identity() @ Vec2d(1, 2)
Vec2d(1, 2)
>>> Transform.scaling(2) @ Vec2d(1, 2)
Vec2d(2, 4)
>>> Transform.translation(3,5) @ Vec2d(1, 2)
Vec2d(4, 7)
>>> Transform.rotation(1) @ Vec2d(1, 2) == Vec2d(1, 2).rotated(1)
True

"""
assert (
len(other) == 2 or len(other) == 6
), f"{other} not supported. Only Vec2d, Transform and Sequence of length 2 or 6 are supported."

if len(other) == 2:
assert len(other) == 2
x, y = cast(Tuple[float, float], other)
return Vec2d(
self.a * x + self.c * y + self.tx, self.b * x + self.d * y + self.ty
)
else:
a, b, c, d, tx, ty = cast(Tuple[float, float, float, float, float, float], other)
return Transform(
a=self.a * a + self.c * b + self.tx * 0,
b=self.b * a + self.d * b + self.ty * 0,
c=self.a * c + self.c * d + self.tx * 0,
d=self.b * c + self.d * d + self.ty * 0,
tx=self.a * tx + self.c * ty + self.tx * 1,
ty=self.b * tx + self.d * ty + self.ty * 1,
)

[docs]
@staticmethod
def identity() -> "Transform":
"""The identity transform

Example:

>>> Transform.identity()
Transform(a=1, b=0, c=0, d=1, tx=0, ty=0)

Returns a Transform with this matrix:

= = =
1 0 0
0 1 0
0 0 1
= = =

"""
return Transform(1, 0, 0, 1, 0, 0)

[docs]
def translated(self, x: float, y: float) -> "Transform":
"""Translate this Transform and return the result.

Example:
>>> Transform.scaling(2).translated(3,4)
Transform(a=2, b=0, c=0, d=2, tx=6, ty=8)

"""
return self @ Transform.translation(x, y)

[docs]
def scaled(self, s: float) -> "Transform":
"""Scale this Transform and return the result.

Example:

>>> Transform.translation(3,4).scaled(2)
Transform(a=2, b=0, c=0, d=2, tx=3, ty=4)
"""
return self @ Transform.scaling(s)

[docs]
def rotated(self, t: float) -> "Transform":
"""Rotate this Transform and return the result.

>>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1).rotated(0.5)
'0.07, 1.00, -1.00, 0.07, 0.00, 0.00'
>>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1.5)
'0.07, 1.00, -1.00, 0.07, 0.00, 0.00'
"""
return self @ Transform.rotation(t)

[docs]
@staticmethod
def translation(x: float, y: float) -> "Transform":
"""A translation transform

Example to translate (move) by 3 on x and 5 in y axis:

>>> Transform.translation(3, 5)
Transform(a=1, b=0, c=0, d=1, tx=3, ty=5)

Returns a Transform with this matrix:

= = =
1 0 x
0 1 y
0 0 1
= = =

"""
return Transform(tx=x, ty=y)

# split into scale and scale_non-uniform

[docs]
@staticmethod
def scaling(s: float) -> "Transform":
"""A scaling transform

Example to scale 4x:

>>> Transform.scaling(4)
Transform(a=4, b=0, c=0, d=4, tx=0, ty=0)

Returns a Transform with this matrix:

= = =
s 0 0
0 s 0
0 0 1
= = =

"""
return Transform(a=s, d=s)

[docs]
@staticmethod
def rotation(t: float) -> "Transform":
"""A rotation transform

Example to rotate by 1 rad:

>>> '%.2f, %.2f, %.2f, %.2f, %.2f, %.2f' % Transform.rotation(1)
'0.54, 0.84, -0.84, 0.54, 0.00, 0.00'

Returns a Transform with this matrix:

====== ======= =
cos(t) -sin(t) 0
sin(t) cos(t)  0
0      0       1
====== ======= =

"""
c = math.cos(t)
s = math.sin(t)
return Transform(a=c, b=s, c=-s, d=c)

```