2015-10-17 9 views
5

Ho una matrice numpy 3d che descrive un polycube (immagina un pezzo di tetris 3d). Come posso calcolare tutte le 24 rotazioni?Come calcolare tutte le 24 rotazioni dell'array 3d?

Numpy's array manipulation routines include un metodo rot90, che fornisce 4 dei 24, ma non ho capito come calcolare il resto. La mia unica idea è di convertire l'array 3d in una matrice 2d di coordinate, moltiplicare per una matrice di rotazione e riconvertire. Ma preferirei lavorare direttamente con l'array 3d.

Esempio 2x2x2 matrice:

>>> from numpy import array 
>>> polycube 
array([[[1, 0], 
     [1, 0]], 

     [[1, 1], 
     [0, 0]]]) 

Esempio 3x3x3 matrice:

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: voglio solo i 24 isometrie orientamento conservativi, non tutte le 48 rotazioni e riflessioni (anche se sarebbe interessante per sapere come farli anche loro). Se aiuta a testare, credo che l'esempio 3x3x3 non abbia simmetria rotazionale ed è chirale (quindi i 48 sono distinti).

Motivazione: Sto scrivendo un risolutore per uno stile Soma cube.

+0

È possibile utilizzare i metodi fliplr e flipud per generare le altre rotazioni, in combinazione con il rot90, credo che sia – tobspr

+1

. 'fliplr' e' flipud' stanno invertendo l'orientamento, quindi so che non posso usarli da soli. Voglio solo isometrie che preservano l'orientamento (24 non 48). –

+1

Proprio come esercizio mentale: è importante notare come questo sia diverso da una nozione più comune di "rotazione 3D". Di solito, si prende una serie di N punti di punti 3D (matrice Nx3) e si moltiplica per una matrice di rotazione 3D (matrice 3x3), ottenendo come risultato un'altra matrice Nx3, dove ogni colonna sarebbe la colonna precedente (un singolo punto 3D) ruotato. Ciò che viene chiesto è molto diverso, poiché la matrice originale è MxNxO (tre assi anziché uno o due dal caso più comune). – heltonbiker

risposta

1

Finora sono 12 di loro, componendo numpy.transpose per permutare i assi (xyz, YZX, zxy-tutti uguali manualità) e 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 

Test rapido del 12 sono distinti: len(set(str(x) for x in rotations(polycube)))


Aggiornamento: ecco come ho fatto tutto 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) 

Usando questa funzione di supporto generalizzare rot90 per ruotare intorno a un asse:

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 

mi rendo conto che la funzione di supporto potrebbe non essere abbastanza di destra, ma ha funzionato

edit: correzione in funzione di supporto m = numpy.rot90 (m, k)

4

Vedere code for rot90. Vedo 3 variazioni su flip e swapaxes, a seconda del parametro dell'asse k.

fliplr(m).swapaxes(0, 1) 
fliplr(flipud(m)) 
fliplr(m.swapaxes(0, 1)) 

fliplr(m) è solo m[:, ::-1], e non sorprendentemente, è flipudm[::-1, ...].

È possibile capovolgere il terzo asse con m[:,:,::-1] o m[...,::-1].

np.transpose è un altro strumento per gli assi di permutazione, che può essere o non essere più facile da usare rispetto a swapaxes.

Se rot90 ti dà 4 delle rotazioni, dovresti essere in grado di applicare le stesse routine per produrre gli altri. Devi solo capire la logica sottostante rot90.

ad es.

def flipbf(m): 
    return m[:,:,::-1] 

flipbf(m).swapaxes(0, 2) 
flipbf(m).swapaxes(1, 2) 
etc 
+0

Non sono sicuro che il flipping/mirroring debba essere considerato come una rotazione 3D corretta, poiché cambia [chirality] (https://en.wikipedia.org/wiki/Chirality) – heltonbiker

+0

(Beh, a meno che, naturalmente, non si componga il flipping e scambiare come hai fatto. Intelligente!) – heltonbiker

+0

Questo potrebbe essere. Suppongo che l'OP sappia cosa sta facendo usando 'rot90'. – hpaulj

1

Un'altra opzione consiste nel combinare le rotazioni attorno all'asse del cubo che rappresenta la matrice. Qualcosa di simile:

import numpy as np 


""" 
Basic rotations of a 3d matrix. 
---------- 
Example: 

cube = array([[[0, 1], 
       [2, 3]], 

       [[4, 5], 
       [6, 7]]]) 

axis 0: perpendicular to the face [[0,1],[2,3]] (front-rear) 
axis 1: perpendicular to the face [[1,5],[3,7]] (lateral right-left) 
axis 2: perpendicular to the face [[0,1],[5,4]] (top-bottom) 
---------- 
Note: the command m[:, ::-1, :].swapaxes(0, 1)[::-1, :, :].swapaxes(0, 2) rotates the cube m 
around the diagonal axis 0-7. 
""" 


def basic_rot_ax(m, ax=0): 
    """ 
    :param m: 3d matrix 
    :return: rotate the cube around axis ax, perpendicular to the face [[0,1],[2,3]] 
    """ 

    ax %= 3 

    if ax == 0: 
     return np.rot90(m[:, ::-1, :].swapaxes(0, 1)[::-1, :, :].swapaxes(0, 2), 3) 
    if ax == 1: 
     return np.rot90(m, 1) 
    if ax == 2: 
     return m.swapaxes(0, 2)[::-1, :, :] 


def axial_rotations(m, rot=1, ax=2): 
    """ 
    :param m: 3d matrix 
    :param rot: number of rotations 
    :param ax: axis of rotation 
    :return: m rotate rot times around axis ax, according to convention. 
    """ 

    if len(m.shape) is not 3: 
     assert IOError 

    rot %= 4 

    if rot == 0: 
     return m 

    for _ in range(rot): 
     m = basic_rot_ax(m, ax=ax) 

    return m 

Se non mi sbaglio, le 24 rotazioni si sta cercando sono una combinazione di questi 9 trasformazioni.

Problemi correlati