Алгоритм построения 4-связной линии

Я ищу алгоритм (кодирование на Java было бы неплохо, но все, что достаточно ясно, чтобы перевести на Java - это хорошо), чтобы нарисовать 4-подключенную линию. Кажется, что алгоритм Брешенема является наиболее широко используемым, но все понятные реализации, которые я нашел, связаны с 8-ми. OpenCV cvline, по-видимому, имеет 4-подключенную версию, но исходный код для меня является посредственным и почти C-неграмотным программистом, непроницаемым, Различные другие поиски ничего не изменили.

Спасибо за любую помощь, которую любой может предоставить.

Ответ 1

Ниже приведен алгоритм, подобный Брешенему, который рисует 4-связанные строки. Код находится на Python, но я полагаю, это легко понять, даже если вы не знаете язык.

def line(x0, y0, x1, y1, color):
    dx = abs(x1 - x0)    # distance to travel in X
    dy = abs(y1 - y0)    # distance to travel in Y

    if x0 < x1:
        ix = 1           # x will increase at each step
    else:
        ix = -1          # x will decrease at each step

    if y0 < y1:
        iy = 1           # y will increase at each step
    else:
        iy = -1          # y will decrease at each step

    e = 0                # Current error 

    for i in range(dx + dy):
        draw_pixel(x0, y0, color)
        e1 = e + dy
        e2 = e - dx
        if abs(e1) < abs(e2):
            # Error will be smaller moving on X
            x0 += ix
            e = e1
        else:
            # Error will be smaller moving on Y
            y0 += iy
            e = e2

Идея состоит в том, что для рисования линии вы должны увеличивать X и Y с соотношением, которое соответствует DX/DY теоретической линии. Для этого я начинаю с переменной error e, инициализированной до 0 (мы находимся в строке), и на каждом шаге я проверяю, является ли ошибка ниже, если я только увеличиваю X или только я приращение Y (проверка Bresenham - это выбор между изменением только X или обоих X и Y).

Наивная версия для выполнения этой проверки заключалась бы в добавлении 1/dy или 1/dx, но умножение всех приращений на dx*dy позволяет использовать только целочисленные значения и улучшает скорость и точность, а также избегает необходимости особых случаев для dx==0 или dy==0, что упрощает логику. Конечно, поскольку мы ищем ошибку пропорции, использование масштабированного приращения не влияет на результат.

Независимо от того, что представляет собой квадрант линии, две возможности для приращения всегда будут иметь различный знаковый эффект на ошибку... поэтому мой произвольный выбор заключался в том, чтобы увеличить ошибку для шага X и уменьшить ошибку для шага Y.

Переменные ix и iy - это реальные направления, необходимые для линии (либо +1, либо -1) в зависимости от того, являются ли исходные координаты более низкими или более высокими, чем конечные координаты.

Количество пикселов для рисования в 4-связанной строке, очевидно, dx+dy, поэтому я просто делаю цикл для этого много раз, чтобы нарисовать линию, а не проверять, попал ли я в конечную точку. Обратите внимание, что этот алгоритм рисует все пиксели, кроме последнего; если вы хотите также, чтобы конечный пиксель затем добавлял дополнительный вызов draw_pixel после окончания цикла.

Пример результата приведенной выше реализации можно увидеть на следующем рисунке

enter image description here

Ответ 2

Для Python-неграмотного здесь приведена версия C версии 6502:

void drawLine(int x0, int y0, int x1, int y1) {
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int sgnX = x0 < x1 ? 1 : -1;
    int sgnY = y0 < y1 ? 1 : -1;
    int e = 0;
    for (int i=0; i < dx+dy; i++) {
        drawPixel(x0, y0);
        int e1 = e + dy;
        int e2 = e - dx;
        if (abs(e1) < abs(e2)) {
            x0 += sgnX;
            e = e1;
        } else {
            y0 += sgnY;
            e = e2;
        }
    }
}