Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotating rectangular array by 45 degrees

Suppose:

2D array:  abcdef
           ghijkl
           mnopqr

Stored in simple string of length width * height, thus, let's call it arr.

arr = abcdefghijklmnopqr
width = 6
height = strlen ( arr ) / width

The goal is to rotate this array by 45 degrees ( PI/4 ) and get the following result:

arr = abgchmdinejofkplqr
width = 3
height = 8
converted to 2D array:  a..
                        bg.
                        chm
                        din
                        ejo
                        fkp
                        .lq
                        ..r

I have spent a few hours trying to figure out how to make this conversion and came up with a few semi-functional solutions, but I can't get it fully working. Can you describe / write an algorithm that would solve this? Preferably in C.

Thanks for any help

Edit: This is what I've tried already
Edit2: The purpose of 45 degree rotation is to turn diagonals into lines so that they can be searched using strstr.

// this is 90 degree rotation. pretty simple
for ( i = 0; i < width * height; i++ ) {
  if ( i != 0 && !(i % height) ) row++;
  fieldVertical[i] = field[( ( i % height ) * width ) + row];
}   

// but I just can't get my head over rotating it 45 degrees. 
// this is what I've tried. It works untile 'border' is near the first edge.

row = 0;
int border = 1, rowMax = 0, col = 0; // Note that the array may be longer
// than wider and vice versa. In that case rowMax should be called colMax.

for ( i = 0; i < width * height; ) { 
  for ( j = 0; j < border; j++, i++ ) {
    fieldCClockwise[row * width + col] = field[i];
    col--;
    row++;
  }

  col = border;
  row = 0;
  border++;
}

The 'border' in my code is an imaginary borderline. In the source, it is a diagonal line that separates diagonals. In the result, it would be a horizontal line between each row.

1   2   3 / 4   5
6   7 / 8   9   10
11 /12  13  14  15

Those slashes are our borderline. The algorithm shoul be pretty simple and just read riagonals: first number 1, then 2, then 6, then 3, then 7, then 11, then 4 and so on.


1 Answers

I looked at http://en.wikipedia.org/wiki/Shear_mapping for inspiration and produced this python code:

a = [['a', 'b', 'c', 'd', 'e', 'f'],
     ['g', 'h', 'i', 'j', 'k', 'l'],
     ['m', 'n', 'o', 'p', 'q', 'r']]

m = 1 # 1/m = slope

def shear_45_ccw(array):
    ret = []
    for i in range(len(array)):
        ret.append([0] * 8)
        for j in range(len(array[i])):
            ret[i][int(i + m * j)] = array[i][j]
    return ret

print(shear_45_ccw(a))

produces:

[['a', 'b', 'c', 'd', 'e', 'f', 0, 0], 
 [0, 'g', 'h', 'i', 'j', 'k', 'l', 0], 
 [0, 0, 'm', 'n', 'o', 'p', 'q', 'r']]

which is something like what you want. The algorithm is hopefully readable even though its in python. The meat of it is this: ret[i][int(i + m * j)] = array[i][j]. Good luck! I cheated when I initialized the array; you'll have to deal with that differently in C anyways.

EDIT: also, I had no idea why your result was flipped and stuff: I trust you can make the right behavior happen.

like image 57
nair.ashvin Avatar answered Aug 28 '26 06:08

nair.ashvin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!