У меня есть двумерный массив, в котором я бы хотел повернуть по диагонали. Я хочу ограничить диапазон между двумя точками, создавая прямоугольную область с квадратом 45 *.
Некоторые примеры:
| - - - - - - - - | - - - - - - - - | - - - - - - - -
| - - - * - - - - | - - - * - - - - | - - - - - * - -
| - - 1 1 1 - - - | - - 1 1 1 - - - | - - - - 1 - - -
| - - 1 1 1 1 - - | - 1 1 1 1 1 - - | - - - 1 - - - -
| - - - 1 1 1 1 - | - - 1 1 1 - - - | - - 1 - - - - -
| - - - - 1 1 1 - | - - - * - - - - | - * - - - - - -
| - - - - - * - - | - - - - - - - - | - - - - - - - -
| - - - - - - - - | - - - - - - - - | - - - - - - - -
*
= входная точка
1
= указать, чтобы итерация
Мой вопрос: как бы я (или подходил) что-то вроде этого чистым и эффективным способом? Заказ не имеет значения.
Это забавная проблема! Вот как бы я решил:
Позвольте идентифицировать 9 различных возможных сценариев:
(Я разместил круги там как руководство для глаза. Я визуализировал эти две точки как "вращение" друг с другом).
Технически случаи от B до I соответствуют двум случаям, в зависимости от того, задана ли верхняя/левая координата первой или нижней/правой, но давайте просто определим желаемый порядок для точек и при необходимости переключим их.
Область, которая должна быть обработана, может быть разбита на параллелограмм (зеленый) и два треугольника:
В случаях C, D и E параллелограмм может обрабатываться "по вертикали" (т. Е. Для каждой x-позиции, вы пробегаете определенное количество точек вдоль вертикали), а в случаях G, H и I это может обрабатываться "горизонтально".
Высота каждого столбца в вертикальном параллелограмме и ширина каждой строки горизонтального параллелограмма - это просто абсолютная разница между y-разностью двух точек и x-разностью двух точек.
Мы можем охватывать все сценарии, обрабатывая только 4 случая: C, E, G и I. B и D можно рассматривать как частный случай C, где параллелограмм имеет высоту или ширину 0 соответственно. Аналогично, F является лишь частным случаем E, а H можно обрабатывать вместе с I. А также может быть добавлен с помощью C, но так как его достаточно легко идентифицировать, давайте рассматривать его отдельно для повышения производительности.
Чтобы сделать программу общей, позвольте мне определить интерфейс для Processor
который взаимодействует с вашим массивом и вызывается для всех координат, которые необходимо обработать:
public interface Processor {
public void process(int x, int y);
}
Код немного длинный, но это не особенно сложно, поэтому позвольте мне просто опубликовать его:
public void process(Processor processor, int x1, int y1, int x2, int y2) {
int dy = Math.abs(y2 - y1);
int dx = Math.abs(x2 - x1);
if (dx<=dy) {
if (dy==0) {
// Case A
processor.process(x1, y1);
return;
}
// Cases B, C, D, E, and F
if (y2>y1) processVertically (processor, x1, y1, x2, y2, dy - dx);
else processVertically (processor, x2, y2, x1, y1, dy - dx);
} else {
// Cases G, H, and I
if (x2>x1) processHorizontally(processor, x1, y1, x2, y2, dx - dy);
else processHorizontally(processor, x2, y2, x1, y1, dx - dy);
}
}
private void processVertically(Processor processor, int x1, int y1, int x2, int y2, int h) {
if (x2<x1) {
// Cases E and F
// Fill in parallelogram
int y = y2;
for (int x=x2; x<=x1; x++) {
for (int dy=0; dy<=h; dy++)
processor.process(x, y-dy);
y--;
}
// Fill in triangles
for (h-=2; h>=0; h-=2) {
x1++; y1++;
x2--; y2--;
for (int dy=0; dy<=h; dy++) {
processor.process(x1, y1+dy);
processor.process(x2, y2-dy);
}
}
} else {
// Cases B, C and D
// Fill in parallelogram
int y = y1;
for (int x=x1; x<=x2; x++) {
for (int dy=0; dy<=h; dy++)
processor.process(x, y+dy);
y++;
}
// Fill in triangles
for (h-=2; h>=0; h-=2) {
x1--; y1++;
x2++; y2--;
for (int dy=0; dy<=h; dy++) {
processor.process(x1, y1+dy);
processor.process(x2, y2-dy);
}
}
}
}
private void processHorizontally(Processor processor, int x1, int y1, int x2, int y2, int w) {
if (y2<y1) {
// Case G
// Fill in parallelogram
int x = x2;
for (int y=y2; y<=y1; y++) {
for (int dx=0; dx<=w; dx++)
processor.process(x-dx, y);
x--;
}
// Fill in triangles
for (w-=2; w>=0; w-=2) {
x1++; y1++;
x2--; y2--;
for (int dx=0; dx<=w; dx++) {
processor.process(x1+dx, y1);
processor.process(x2-dx, y2);
}
}
} else {
// Cases H and I
// Fill in parallelogram
int x = x1;
for (int y=y1; y<=y2; y++) {
for (int dx=0; dx<=w; dx++)
processor.process(x+dx, y);
x++;
}
// Fill in triangles
for (w-=2; w>=0; w-=2) {
x1++; y1--;
x2--; y2++;
for (int dx=0; dx<=w; dx++) {
processor.process(x1+dx, y1);
processor.process(x2-dx, y2);
}
}
}
}
process(...)
-method просто определяет, какой из 9 случаев у нас есть, и либо обрабатывает случай A напрямую, либо вызывает processHorizontally(...)
или processVertically(...)
как описано выше. Затем эти методы проходят через соответствующие параллелограммы и заполняют треугольники вокруг параллелограмма после.
Несколько вещей, чтобы отметить:
processHorizontally(...)
и processVertically(...)
являются точно такими же, кроме обмена x и y.processor.process(...)
процесса processor.process(...)
, обработка случаев B и F отдельно в более оптимизированный способ,...).process(...)
может быть вызван с отрицательными координатами!Надеюсь это поможет. Дайте мне знать, если вам нужно более подробное объяснение кода.