Colonel Panic Colonel Panic - 24 days ago 8
Python Question

How to calculate all 24 rotations of 3d array?

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

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)

Comments