Самый чистый способ генерировать 8-соседние координаты
Я ищу способ генерировать следующую последовательность чисел (которые являются относительными координатами 8 соседей пикселя, начиная с северо-западного пикселя и заканчивая западным). Первое число - это координата y, а второе - координата x:
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
Я могу придумать несколько уродливых способов сделать это, например, просто поместить координаты в массив, но мне интересно, есть ли чистый и эффективный способ, о котором я не думал.
Редактировать: в связи с тем, как спроектирован алгоритм, который я пытаюсь реализовать, пиксели должны быть перебраны в определенном порядке (от NW до W).
2 ответа
Рассмотрим следующий метод генерации только Y-координат.
Начиная с NW мы хотим достичь {1, 1, 1, 0, -1, -1, -1, 0}. Это повторяющийся шаблон, заданный циклом:
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;
}
Так что это сгенерирует желаемую последовательность для значений y.
Теперь рассмотрим последовательность значений x, начиная с NE: {1, 1, 1, 0, -1, -1, -1, 0}. Вы можете видеть, что это та же самая последовательность.
Таким образом, мы можем создать желаемую последовательность, начиная с NW, используя смещение 2 к предыдущему циклу и добавление последней тройки, чтобы разместить перенос в конце последовательности:
for (int i = 2; i < 10; i++ )
{
int x = (i % 4 == 3) ? 0 : 1;
x *= (i % 8 > 3) ? 1 : -1;
}
Теперь тривиально объединить два в один цикл:
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;
}
Другая удобочитаемая альтернатива - явно перечислить стороны следующим образом:
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
*/
Это дает дополнительное преимущество, заключающееся в том, что окрестность любого размера может быть пройдена путем изменения начального угла и количества шагов вдоль стороны.
@louism: "Я могу придумать несколько уродливых способов сделать это, например, просто поместить координаты в массив" - я думаю, что это лучший способ, на самом деле. Он понятен и читаем (в отличие от метода арифметики модулей, описанного в @ose выше) и, возможно, самый быстрый.
@louism: не могли бы вы сравнить три различных метода (поиск в массивах, перечислить стороны, арифметику модуля) и опубликовать результаты? Я был бы весьма заинтересован в этом, так как это то, что я бы использовал в коде, который я пишу прямо сейчас.