Search code examples
language-agnosticpixelflip-flop

Cleanest way to generate 8-neighbour coordinates


I'm looking for a way to generate the following sequence of numbers (which are the relative coordinates of a pixel's 8 neighbours, starting with the north-west pixel and ending with the west). The first number is the y-coordinate and the second is the x-coordinate:

 y,  x
 _____

 1, -1   // N-W
 1,  0   // N
 1,  1   // N-E
 0,  1   // E
-1,  1   // S-E
-1,  0   // S
-1, -1   // S-W
 0, -1   // W

I can dream up several ugly ways to accomplish this, such as just putting the coordinates in an array, but I'm wondering if there's a clean and efficient way I haven't thought of.

Edit: due to the way the algorithm I'm trying to implement is designed, the pixels must be iterated in that particular order (N-W to W).


Solution

  • Consider the following method of generating the Y-coords first only.

    Starting from NW we want to achieve {1, 1, 1, 0, -1, -1, -1, 0}. This is a repeating pattern given by the loop:

    for( int i = 0; i < 8; i++ )
    {
        // You can combine into one ternary if you are adventurous
        int y = (i % 4 == 3) ? 0 : 1;
        y *= (i > 3) ? -1 : 1;
    }
    

    So this will generate the desired sequence for the y-values.

    Now consider the sequence of x values starting from NE: {1, 1, 1, 0, -1, -1, -1, 0 }. You can see it is the same sequence.

    So we can produce the desired sequence starting from NW using an offset of 2 to the previous loop and doctoring the last ternary to accommodate the wrapping at the end of the sequence:

    for (int i = 2; i < 10; i++ )
    {
        int x = (i % 4 == 3) ? 0 : 1;
        x *= (i % 8 > 3) ? 1 : -1;   
    }
    

    Now it is trivial to combine the two into a single loop:

    for (int i = 0; i < 8; i++)
    {
        int y = (i % 4 == 3) ? 0 : 1;
        y *= (i > 3) ? -1 : 1;
    
        int x = ( (i+2) % 4 == 3) ? 0 : 1;
        x *= ( (i+2) % 8 > 3) ? 1 : -1;
    }