Итерация по двумерному массиву по диагонали между двумя точками

1

У меня есть двумерный массив, в котором я бы хотел повернуть по диагонали. Я хочу ограничить диапазон между двумя точками, создавая прямоугольную область с квадратом 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= указать, чтобы итерация

Мой вопрос: как бы я (или подходил) что-то вроде этого чистым и эффективным способом? Заказ не имеет значения.

  • 0
    Вы пытались решить проблему? Если это так, пожалуйста, покажите нам свою попытку.
  • 1
    У меня есть, но в нем задействовано 13 различных int-переменных и ... вообще не работает, поэтому я думаю, что опубликовать его будет только отвлекать от вопроса
Показать ещё 5 комментариев
Теги:
arrays
multidimensional-array

1 ответ

5
Лучший ответ

Это забавная проблема! Вот как бы я решил:

Позвольте идентифицировать 9 различных возможных сценариев:

Изображение 174551

(Я разместил круги там как руководство для глаза. Я визуализировал эти две точки как "вращение" друг с другом).

  • А - тривиальный случай, когда обе координаты одинаковы
  • B и F - случаи, когда вам в основном нужно нарисовать диагональную линию
  • C, D и E - случаи, когда y-расстояние между точками больше, чем x-расстояние
  • G, H и I - случаи, когда x-расстояние между точками больше y-distance

Технически случаи от B до I соответствуют двум случаям, в зависимости от того, задана ли верхняя/левая координата первой или нижней/правой, но давайте просто определим желаемый порядок для точек и при необходимости переключим их.

Область, которая должна быть обработана, может быть разбита на параллелограмм (зеленый) и два треугольника:

Изображение 174551

В случаях 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(...) как описано выше. Затем эти методы проходят через соответствующие параллелограммы и заполняют треугольники вокруг параллелограмма после.

Несколько вещей, чтобы отметить:

  1. В принципе, processHorizontally(...) и processVertically(...) являются точно такими же, кроме обмена x и y.
  2. Циклы довольно жесткие и не включают в себя какую-либо тяжелую математику, поэтому этот код должен быть достаточно эффективным, но определенно есть еще возможность для улучшения (например, вложение processor.process(...) процесса processor.process(...), обработка случаев B и F отдельно в более оптимизированный способ,...).
  3. Этот код не проверяет границы массива! Например, process(...) может быть вызван с отрицательными координатами!
  4. Можно сказать: Case G и case E выглядят почти как в одном и том же случае. Разве вы не можете просто рассчитать два других угла прямоугольника, чтобы отобразить случай G на случай E и H на D и I на C вместо того, чтобы рассматривать их как отдельные случаи? И в идеальной математике это совершенно правильное утверждение, за исключением того, что оно не работает в тех случаях, когда координаты других углов не являются целыми числами. Например, это имеет место в первом примере OP. Там у вас есть "расколотый" угол (всего два в столбце) слева и справа. Если вы должны были вычислять и окружать левый и правый углы прямоугольника, а не верхний и нижний углы, вы окажетесь "нарезанные" углы сверху и снизу.

Надеюсь это поможет. Дайте мне знать, если вам нужно более подробное объяснение кода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню