Module dslib:rotnum

Numbers for 90 degree rotations.

This module provides so-called rotnums: numbers that can represent rotations of multiples of 90°, mirrorings and compositions of those.

Rotnums can be used to rotate arbitrary spatial vectors. They can be converted to and from facedir and wallmounted values and euler angles.

Note: Rotnums are numbers, not tables, so you can't do method calls and similar on them.

For every rotation or other transformation, there is one unique rotnum. So, one can compare rotnums using == and use rotnums as table keys.

How they work

Rotnums are actually a compact representation for a special kind of 3x3 matrices, which have in each row only one element that is non-zero, and this element is either 1 or -1, for example:

( 0 -1  0 )
( 0  1  0 ) is equivalent to 0x415
(-1  0  0 )

comp and apply are just matrix multiplication.

See also [Bit representation] for details.

Bit representation

A rotnum is a 11-bit integral number that the following bits (in MSBF (most significant bit first) notation):

sz z1 z0 0 sy y1 y0 0 sx x1 x0

A vector v_in is transformed to a vector v_out using these bits in the following way:

  • The 0-bits are padding.
  • Let w be any of x, y, z.
  • w1 w0 says for v_out.w which component of v_in it should be: 0b00 for x, 0b01 for y and 0b10 for z.
  • If sw == 1, the w component in v_out is negated.
  • Example: For 0 sx x1 x0 == 0b0110, v_out.x = -v_in.z.

You may assume that the representation of rotnums stays the same (until a major version change, see Versioning.md). Hence, storing rotnums in meta and similar is valid.

Caching

Some functions, such as rotnum.rjw(), are documented to return a constant.

You can cache the return values instead of the functions:

local r2x = rotnum.r2x -- what you would normally do
local r2x = rotnum.r2x() -- valid

Functions

comp (a, b) Composition of two rotnums.
apply (n, vec) Apply a rotnum to a vector.
inv (rn) The inverse.
can_inv (rn) Checks whether a rotnum is invertible.
is_rotnum (obj) Checks whether something is a valid rotnum.
compj (rn1, ...) Composition of j rotnums.
compn (rns) Composition of many rotnums.
compjapply (rn1, ..., vec) Composition of j rotnums and application on a vector.
compnapply (rns, vec) Composition of many rotnums and application on a vector.
id () Identity.
rjw () Rotates j*90 degrees around the +w axis.
rljw () Alias for rotnum.rjw().
rrjw () Alias for rotnum.r(4-j)w().
rnw (n) Rotates a multiple of 90 degrees around the +w axis.
rlnw (n) Alias for rotnum.rnw(n).
rrnw (n) Alias for rotnum.rnw(-n).
rn_around (n, dir) Rotate a multiple of 90 degrees around the given axis.
rln_around (n, dir) Alias for rotnum.rn_around(n, dir).
rrn_around (n, dir) Alias for rotnum.rn_around(-n, dir).
mirror_w () Mirrors along the w axis.
mirror_along (dir) Mirror along given axis.
from_facedir (facedir) Converts a facedir number to a rotnum.
to_facedir (rn) Tries to convert a rotnum to a facedir number.
wallmounted_to_facedir (wallmounted) Converts a wallmounted number to a facedir number.
facedir_to_wallmounted (facedir) Tries to convert a facedir number to a wallmounted number.
from_wallmounted (wallmounted) Converts a wallmounted number to a rotnum.
to_wallmounted (rn) Tries to convert a rotnum to a wallmounted number.
apply_facedir (facedir, vec) Apply a facedir number to a vector.
apply_wallmounted (wallmounted, vec) Apply a wallmounted number to a vector.
from_euler (euler_vec) (Rounds and) converts an euler angle vector to a rotnum.
to_euler (rn) Tries to convert a rotnum to euler angles.


Functions

comp (a, b) line 105

Composition of two rotnums.

Applying the returned rotnum is the same as first applying b and then a.

This operation is:

  • associative: rotnum.comp(a, rotnum.comp(b, c)) == rotnum.comp(rotnum.comp(a, b), c)
  • not commutative: rotnum.comp(a, b) ~= rotnum.comp(b, a)

Parameters:

  • a rotnum
  • b rotnum

Returns:

    rotnum The composition (a after b).
apply (n, vec) line 128

Apply a rotnum to a vector.

This operation is:

  • associative with rotnum.comp: rotnum.apply(a, rotnum.apply(b, v)) == rotnum.apply(rotnum.comp(a, b), v)
  • distributive with vector addition: rotnum.apply(a, v1 + v2) == rotnum.apply(a, v1) + rotnum.apply(a, v2)

Parameters:

  • n rotnum The rotnum to apply.
  • vec vector The vector to transform.

Returns:

    vector The transformed vector.
inv (rn) line 163

The inverse.

Applying the result undoes the given rotnum's transformation.

Warning: Not all rotnums have an inverse (see can_inv for details). If the given rotnum has no inverse, the output is some integral number with undefined properties.

Example:

assert(rotnum.id() == rotnum.comp(rn, rotnum.inv(rn)))
assert(rotnum.inv(rotnum.comp(rn1, rn2)) == rotnum.comp(rotnum.inv(rn2), rotnum.inv(rn1)))

This operation just transposes the rotnum (because invertible rotnums are orthonormal).

This function can also be used to find out where each of the +x, +y and +z would be transformed to by the given rotnum:

  • In the input rotnum, sw w1 w0 says from what the w-component will be created.
  • In the output rotnum, sw w1 w0 says to what the w-component will be transformed.

Parameters:

  • rn rotnum

Returns:

    rotnum
can_inv (rn) line 187

Checks whether a rotnum is invertible.

The following statements are equivalent:

  • rn is invertible.
  • rn is a rotation, a mirroring or a composition of those.
  • The matrix represented by rn has 1 or -1 in each column.
  • The matrix represented by rn is orthonormal.
  • The inverse of rn is its transposed.
  • The transposed of the matrix represented by rn can be represented by a rotnum.
  • The matrix represented by rn has full rank.
  • The determinant of the matrix represented by rn is either 1 or -1.

Parameters:

  • rn rotnum The rotnum to check.

Returns:

    bool true if rn is invertible, false otherwise.
is_rotnum (obj) line 199
Checks whether something is a valid rotnum.

Parameters:

  • obj Some value.

Returns:

    bool true if obj is a rotnum, false otherwise.
compj (rn1, ...) line 230

Composition of j rotnums.

Read this as a template. The compj() function doesn't exist itself. j can be any of 2, 3, 4, 5.

These functions can be used as shortcut for multiple calls of comp, ie.:

-- both do the same:
rotnum.comp(rotnum.comp(rn1, rn2), rn3)
rotnum.comp3(rn1, rn2, rn3)

Parameters:

  • rn1 rotnum
  • ... rotnum More rotnums. Number depends on j.

Returns:

    rotnum The compositon of all rotnums.
compn (rns) line 251

Composition of many rotnums.

Example:

rotnum.compn{rn1, rn2, ...}

Parameters:

  • rns table List of rotnums (can be empty).

Returns:

    rotnum The compositon of all rotnums.
compjapply (rn1, ..., vec) line 276

Composition of j rotnums and application on a vector.

Read this as a template. The compjapply() function doesn't exist itself. j can be any of 2, 3, 4, 5.

These functions can be used as shortcut for multiple calls of comp, followed by a call to apply, ie.:

-- both do the same:
rotnum.apply(rotnum.comp(rn1, rn2), vec)
rotnum.comp2apply(rn1, rn2, vec)

Parameters:

  • rn1 rotnum
  • ... rotnum More rotnums. Number depends on j.
  • vec vector The vector to transform.

Returns:

    vector The transformed vector.
compnapply (rns, vec) line 302

Composition of many rotnums and application on a vector.

Example:

rotnum.compnapply({rn1, rn2, ...}, vector.new(1, 0, 0))

Parameters:

  • rns table List of rotnums (can be empty).
  • vec vector The vector to transform.

Returns:

    vector The transformed vector.
id () line 312
Identity.

A vector stays unmodified if you apply the returned rotnum to it.

Returns:

    rotnum A constant.
rjw () line 330
Rotates j*90 degrees around the +w axis.

Read this as a template. The rjw() function doesn't exist itself. j can be any of 1, 2, 3. w can be any of x, y, z. Example: rotnum.r1x()

This is a left-handed rotation in left-handed coord system (equals right-handed rotation in right-handed system). Hence, it's a left-handed rotation in Minetest's left-handed system. (Left-handed rotation is clockwise if you look from the +w side.)

Returns:

    rotnum A constant.
rljw () line 383
Alias for rotnum.rjw().

The l stands for left-handed rotation in a left-handed coordinate system.

Example: rotnum.rl1x == rotnum.r1x

rrjw () line 391
Alias for rotnum.r(4-j)w().

The second r stands for right-handed rotation in a left-handed coordinate system.

Example: rotnum.rr1x == rotnum.r3x

rnw (n) line 424
Rotates a multiple of 90 degrees around the +w axis.

Read this as a template. The rnw() function doesn't exist itself. w can be any of x, y, z. Example: rotnum.rnx()

n will be taken modulo 4 and rounded to the nearest integer.

Parameters:

  • n number How often to rotate.

Returns:

    rotnum One of rotnum.rjw()'s return values, depending on n.
rlnw (n) line 448
Alias for rotnum.rnw(n).

Example: rotnum.rlnx == rotnum.rnx

Parameters:

  • n number

Returns:

    rotnum
rrnw (n) line 460
Alias for rotnum.rnw(-n).

Example: rotnum.rrnx

Parameters:

  • n number

Returns:

    rotnum
rn_around (n, dir) line 481
Rotate a multiple of 90 degrees around the given axis.

The semantics for n are the same as in rotnum.rnw.

Parameters:

  • n number How often to rotate.
  • dir string "x", "y" or "z".

Returns:

    rotnum An output of rotnums.rjw, depending on n and dir.
rln_around (n, dir) line 490
Alias for rotnum.rn_around(n, dir).

Parameters:

Returns:

    rotnum
rrn_around (n, dir) line 496
Alias for rotnum.rn_around(-n, dir).

Parameters:

Returns:

    rotnum
mirror_w () line 509
Mirrors along the w axis.

Read this as a template. The mirror_w() function doesn't exist itself. w can be any of x, y, z. Example: rotnum.mirror_x()

Returns:

    rotnum A constant.
mirror_along (dir) line 526
Mirror along given axis.

Parameters:

Returns:

    rotnum One of rotnum.mirror_w()'s return values, depending on dir.
from_facedir (facedir) line 562
Converts a facedir number to a rotnum.

Parameters:

  • facedir int The facedir number.

Returns:

    rotnum The rotnum.
to_facedir (rn) line 573
Tries to convert a rotnum to a facedir number.

Facedir values can represent any compositions of 90° rotations, but not mirrorings for example. Hence, this can fail.

Parameters:

  • rn rotnum The rotnum.

Returns:

    Facedir number or false on failure.
wallmounted_to_facedir (wallmounted) line 603
Converts a wallmounted number to a facedir number.

Parameters:

  • wallmounted int The wallmounted value.

Returns:

    int The facedir value.
facedir_to_wallmounted (facedir) line 610
Tries to convert a facedir number to a wallmounted number.

Parameters:

  • facedir int The facedir value.

Returns:

    The wallmounted value or false on failure.
from_wallmounted (wallmounted) line 624
Converts a wallmounted number to a rotnum.

Parameters:

  • wallmounted int The wallmounted number.

Returns:

    rotnum The rotnum.
to_wallmounted (rn) line 631
Tries to convert a rotnum to a wallmounted number.

Parameters:

  • rn rotnum The rotnum.

Returns:

    Wallmounted number or false on failure.
apply_facedir (facedir, vec) line 644

Apply a facedir number to a vector.

Shortcut for:

rotnum.apply(rotnum.from_facedir(facedir), vec)

Parameters:

  • facedir int The facedir number.
  • vec vector The vector to transform.

Returns:

    vector The transformed vector.
apply_wallmounted (wallmounted, vec) line 656

Apply a wallmounted number to a vector.

Shortcut for:

rotnum.apply(rotnum.from_wallmounted(wallmounted), vec)

Parameters:

  • wallmounted int The wallmounted number.
  • vec vector The vector to transform.

Returns:

    vector The transformed vector.
from_euler (euler_vec) line 663
(Rounds and) converts an euler angle vector to a rotnum.

Parameters:

  • euler_vec vector The euler vectors.

Returns:

    rotnum
to_euler (rn) line 728
Tries to convert a rotnum to euler angles.

Note: Euler angles can just rotate, hence this call can fail.

Parameters:

  • rn rotnum The rotnum to convert.

Returns:

    The vector of euler angles or false on failure.
generated by LDoc 1.4.6 Last updated 2023-04-02 20:41:54