Как вы рисуете прямую линию между двумя точками в растровом изображении?


17

Я играю с картами высот (растровыми изображениями), пытаюсь создать свои собственные в моей игре, и для этого мне нужно реализовать некоторые базовые методы рисования. Я быстро понял, что рисование прямых линий не так просто, как я думал.

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

Какой алгоритм вы используете, чтобы определить, какие пиксели нужно раскрасить, чтобы он стал «прямой» линией?

Ответы:



21

Алгоритм линии Брезенхэма можно использовать для определения точек в растровой сетке для построения соответствующей визуальной аппроксимации отрезка линии.

Алгоритм охватывает растеризацию линии, определяемой началом координат и конечными точками в координатном пространстве, где начало координат находится слева вверху. Предполагается, что целочисленные координаты сопоставляются с центрами пикселей. Примечательно, что базовая форма алгоритма охватывает только один октант круга: тот, в котором линия имеет увеличивающиеся координаты X и Y, но отрицательный наклон с абсолютным значением меньше 1. Все остальные октанты могут быть получены как простые преобразования этого основной октант.

В psuedocode эта базовая форма выглядит так:

void DrawLine(Point origin, Point endpoint, Bitmap surface) {
    deltaX = endpoint.X - origin.X
    deltaY = endpoint.Y - origin.Y
    error = 0

    // Note the below fails for completely vertical lines.
    deltaError = absoluteValue(deltaY / deltaX)

    Y = origin.Y
    for (X from origin.X to endpoint.X) {
        surface.PlotPixel(X, Y)
        error = error + deltaError 
        if (error >= 0.5) {
            ++Y;
            error -= 1.0
        }
    }
}

На веб-сайте Rosetta Code есть коллекция конкретных реализаций на разных языках .

Вы также можете быть заинтересованы в строковом алгоритме Ву , который допускает сглаживание.


3
Просто хочу предупредить прохожих, чтобы они не вынимали включенный псевдокод из контекста, поскольку он не будет работать из коробки. Это работает только для определенного октанта (прочитайте остальную часть ответа). Если вы ищете код для копирования / вставки, попробуйте ссылку на веб-сайт Rosetta Code.
congusbongus

1
Для тех, кто хочет проверить версию строкового алгоритма У, я хотел бы предупредить вас, что он неполон. В _dla_changebrightness при изменении яркости вы должны изменить его из: to->red = br * (float)from->red;к этому следующее: to->red = (br * (float)from->red) + ((1-br) * (float) to->red);. Сделайте то же самое для зеленого и синего соответственно
Фредрик Бостон Вестман

2

Вот чрезвычайно простой способ рисования линий. Функция может быть легко изменена для использования в проектах.

void draw_line(float x0, float y0, const float& x1, const float& y1)
{
    float x{x1 - x0}, y{y1 - y0};
    const float max{std::max(std::fabs(x), std::fabs(y))};
    x /= max; y /= max;
    for (float n{0}; n < max; ++n)
    {
        // draw pixel at ( x0, y0 )
        x0 += x; y0 += y;
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.