Colonel Panic - 1 year ago 81

Python Question

I have a 3d numpy array describing a polycube (imagine a 3d tetris piece). How can I calculate all 24 rotations?

Numpy's array manipulation routines includes a rot90 method, which gives 4 of the 24, but I'm clueless how to calculate the rest. My only idea is to convert the 3d array to a 2d matrix of co-ordinates, multiply by a rotation matrix, and convert back. But I'd rather work directly with the 3d array.

Example 2x2x2 array:

`>>> from numpy import array`

>>> polycube

array([[[1, 0],

[1, 0]],

[[1, 1],

[0, 0]]])

Example 3x3x3 array:

`array([[[1, 1, 0],`

[1, 1, 0],

[0, 0, 0]],

[[0, 0, 0],

[1, 0, 0],

[1, 0, 0]],

[[0, 0, 0],

[0, 0, 0],

[0, 0, 0]]])

Edit: I only want the 24 orientation-preserving isometries, not all 48 rotations and reflections (though it would be interesting to know how to make them too). If it helps to test, I believe the 3x3x3 example has no rotational symmetry and is chiral (so the 48 are distinct).

Motivation: I'm writing a solver for a Soma cube-style puzzle.

Answer Source

So far I have 12 of them, composing `numpy.transpose`

to permute the axes (xyz, yzx, zxy—all the same handedness) and rot90.

```
def rotations12(polycube):
for i in range(3):
polycube = numpy.transpose(polycube, (1, 2, 0))
for angle in range(4):
polycube = numpy.rot90(polycube)
yield polycube
```

Quick test the 12 are distinct: `len(set(str(x) for x in rotations(polycube)))`

**Update:** here's how I made all 24.

```
def rotations24(polycube):
# imagine shape is pointing in axis 0 (up)
# 4 rotations about axis 0
yield from rotations4(polycube, 0)
# rotate 180 about axis 1, now shape is pointing down in axis 0
# 4 rotations about axis 0
yield from rotations4(rot90(polycube, 2, axis=1), 0)
# rotate 90 or 270 about axis 1, now shape is pointing in axis 2
# 8 rotations about axis 2
yield from rotations4(rot90(polycube, axis=1), 2)
yield from rotations4(rot90(polycube, -1, axis=1), 2)
# rotate about axis 2, now shape is pointing in axis 1
# 8 rotations about axis 1
yield from rotations4(rot90(polycube, axis=2), 1)
yield from rotations4(rot90(polycube, -1, axis=2), 1)
def rotations4(polycube, axis):
"""List the four rotations of the given cube about the given axis."""
for i in range(4):
yield rot90(polycube, i, axis)
```

Using this helper function generalising rot90 to rotate about any axis:

```
def rot90(m, k=1, axis=2):
"""Rotate an array by 90 degrees in the counter-clockwise direction around the given axis"""
m = numpy.swapaxes(m, 2, axis)
m = numpy.rot90(m, k)
m = numpy.swapaxes(m, 2, axis)
return m
```

I realise the helper function might not be quite right, but it worked

edit : correction in helper function m = numpy.rot90(m, k)