Question

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).

Was it helpful?

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;
}

OTHER TIPS

Another readable alternative is to enumerate the sides explicitly, as follows:

int x = -1;
int y = 1;
for (int side = 0; side < 4; side++)
{
    for (int steps = 0; steps < 2; steps++)
    {
        // use coordinates here
        printf("%d, %d\n", y, x);

        if (side == 0) { x++; }
        else if (side == 1) { y--; }
        else if (side == 2) { x--; }
        else /* if side == 3) */ { y++; }
    }
}

/*
result:
1, -1
1, 0
1, 1
0, 1
-1, 1
-1, 0
-1, -1
0, -1
*/

This has the additional benefit that a neighborhood of any size can be traversed by changing the starting corner and the number of steps along a side.

@louism: "I can dream up several ugly ways to accomplish this, such as just putting the coordinates in an array" - I think that is the best way, actually. It is clear and readable (unlike the modulus arithmetic method described by @ose above), and possibly the fastest.

@louism: could you benchmark the three different methods (array lookups, enumerate sides, modulus arithmetic) and post the results? I would be rather interested in this since it is something I would use in code I am writing right now.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top