Найти тему
Разумный мир

Как алгоритм Брезенхема рисует прямые линии

Оглавление

Давно у меня не было статей посвященных вопросам программирования и алгоритмов. Хочется немного отвлечься от метрологии и поговорить на более простые темы. Как компьютер рисует прямые линии, точнее, отрезки прямых? Этот базовый элемент машинной графики. Давайте посмотрим на то, что лежит в основе.

Обращаю ваше внимание, что будет рассматриваться сам принцип работы алгоритма Брезенхема, а не конкретная программная реализация для конкретной машины. То, что лежит за сухими строчками программного кода. Использовать готовый код легко. Гораздо сложнее понять, как же он на самом деле работает.

ВНИМАНИЕ!!! В статье используется математика! Вас предупредили :)

Немного истории вопроса

Когда то давно самого понятия "машинная графика" не существовало. Действительно, что и,самое главное, как, может нарисовать машина? Человек с помощью механических приспособлений рисовать и чертить может, но сама машина нет. С появлением вычислительных машин ситуация начала меняться, но далеко не сразу. Первые ЭВМ умели не многое, не говоря уже о выводе результатов вычислений в виде понятном простому человеку. Какое уж тут рисование...

Технологии развивались, появились алфавитно-цифровые печатающие устройства (АЦПУ). Сначала на базе электрических пишущих машинок, а потом и с параллельной печатью и вращающимся барабаном. Но главное, теперь можно было не только печатать текст, но и простые графические документы, в которых рисунок формировался из текстовых символов. Такое побочное и не профильное использование возможностей печатающих устройств.

Такую своеобразную графику можно увидеть и сегодня, достаточно выполнить поиск по словам "текстовая графика" или "ascii графика". Правда найденные иллюстрации не будут иметь отношения к инженерной графике, но представление о том, как это выглядело получить можно.

При этом одним из первых устройств вывода был и обычный аналоговый осциллограф. Он позволял визуально отобразить функциональную зависимость между двумя переменными. Механической альтернативой являлся графопостроитель (в англоязычной терминологии plotter). Графопостроитель позволял сразу получить документ, который можно было хранить. А управляя положением пера поднято/опущено можно было уже выполнять довольно сложные чертежи.

Осциллограф, как устройство вывода информации, особой популярности не снискал, но его дальним потомком является алфавитно-цифровой дисплей. Правда более удобным способом вывода оказался телевизионный, когда изображение (текст) формируется на основе точек телевизионной развертки - растра. Такие дисплеи называют растровыми.

Если мы позволим использовать все точки растра, а не только в позициях символов, то мы получим графический растровый дисплей. В отличии от алфавитно-цифрового такой дисплей не содержит знакогенератора и требует гораздо большего количества памяти, причем быстродействующей.

Осциллографы и графопостроители дали и еще один тип графических дисплеев - векторные. Они позволяли быстро и не переводя бумагу отображать простые чертежи и фрагменты чертежей. Векторный дисплей формировал изображение не из отдельных точек, а из отрезков прямых, причем они рисовались аппаратно (с точки зрения пользователя дисплея и программиста ЭВМ). В качестве артефакта, алфавитно-цифрового векторного дисплея, можно привести отечественный РИН-609, в котором символы формировались из отрезков прямых.

Векторный и растровый

Мы уже знаем, что растровый дисплей использует точки, изначально телевизионного, растра для формирования изображения. Такой же принцип используется для формирования печатного изображения

Растровое печатное черно-белое изображение. Фото мое
Растровое печатное черно-белое изображение. Фото мое

Только точки не являются точками телевизионного растра, что не изменяется смысла термина "растровый". Растровое изображение состоит из отдельных точек, которые могут занимать строго определенные места. При этом каждая точка может иметь собственные значения атрибутов, например, цвет, яркость, размер. Не важно, что именно за изображение отображается растровым устройством. Это может быть фотография, чертеж, рисунок.

Векторный рисунок состоит не из точек, а из векторов, которые являются отрезками прямых линий. Да, в физике и математике вектор это не просто отрезок прямой, но еще и направленный. Однако, в готовом изображении информация о направлении вектора теряется. Но она является важно во время формирования изображения. Направление движения пера или электронного луча является важным. В отличии от растровых, векторные изображения плохо подходят для фотографий, но вполне подходят для чертежей и рисунков.

Векторное изображение строится точно так же, как мы рисуем карандашом или пером. Мы проводим линии, как прямые, так кривые. И компьютер поступает точно так же. Но если от руки мы можем провести кривую любой формы, то для векторных дисплеев и графопостроителей обычно существует ограниченный набор кривых линий. А иногда все ограничивается и только отрезками прямых.

Основным преимуществом растровых изображений является их "фотографичность" и естественность. То есть, при достаточном малом размере точки (пикселя) и плотном расположении точек, изображение выглядит как полноценная фотография с плавными переходами оттенков цвета и проработанными деталями. Но если мы начнем увеличивать изображение, как вариант, подойдем к нему ближе, мы все таки увидим отдельные точки. И это является недостатком. Впрочем, недостаток вполне компенсируется преимуществами растровых изображений.

Растровые изображения естественны по своей природе. Ведь даже наш глаз воспринимает любое изображение как растровое. Сетчатка состоит из отдельный "точек" в виде чувствительных элементов - палочек и колбочек.

Основным преимуществом векторных изображений является легкость масштабирования. Да, если, например, окружность формируется из отрезков прямых, то при увеличении мы увидим эти отрезки. Но если окружность является полноценным доступных элементом, доступным видом кривой, то качество изображения при увеличении/уменьшении не пострадает. И это важно для графики инженерной, о которой мы сегодня и будем говорить. Ведь чертежи бывают разного размера и часто требуется рассматривать фрагмент чертежа, работать с его частью.

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

Но давайте оставим в стороне вопросы выбора форматов изображений. Точнее, раз мы говорим о машинной инженерной графике, чертежей. В конечном итоге все равно останется проблема вывода векторного изображения на растром устройстве и растрового изображения на векторном. Конечно, фотографии редко выводят на графопостроителях, но иногда требуется просто преобразовать растровое изображение в векторный формат. Этот процесс называется векторизацией и мы сегодня его не будем рассматривать.

Гораздо чаще приходится выводить векторные изображения на растровые устройства отображения. Любой чертеж является векторным изображением. Естественный устройством для вывода готового чертежа в виде бумажного документа является графопостроитель. Но работа с чертежом обычно выполняется на растровых графических дисплеях. Процесс преобразования векторного изображения в растровый формат называется растеризацией.

Естественным элементом векторного изображения является вектор, в простейшем случае отрезок прямой линии. И о растеризации отрезков прямых линий мы и будем сегодня говорить.

А зачем?

Безусловно, специалисты знали все это давно, когда машинная графика еще только зарождалась. Но массовое внимание этот вопрос привлек когда началось массовое распространение персональных ЭВМ (еще простых 8-битных, если говорить о бытовых моделях) и многие пытались освоить на практике программирование для них. С появлением библиотек машинной графики и операционных систем Windows и OS/2 стало проще. Классическая ситуация, когда профессионалы и так знают, а любители пользуются готовым.

После ПК начали массово распространяться и микроконтроллеры, причем в качестве устройств отображения информации тоже начали использовать графические дисплеи, хоть и далеко не всегда. И у любителей снова стал возникать вопрос "Как нарисовать отрезок прямой"? Ведь готовые библиотеки для микроконтроллеров есть не всегда, да и вариантов графических дисплеев здесь гораздо больше.

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

Кстати, алгоритм Брезенхема применим не только для растровых устройств, но и для кажущихся векторными. Например, привод пера в графопостроителях обычно выполняется шаговыми двигателями. А значит, у нас появляются некие "узловые точки" в которых перо "останавливается" (условно останавливается). Только нам здесь важны не эти точки, а то, как перо движется между этими точками.

Что такое прямая линия?

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

Этюд о координатах.
Разумный мир16 мая 2019

Большинство устройств отображения информации, которые используются с компьютерами, являются двумерными. То есть, наша прямая линия будет располагаться на плоскости. Кроме того, в подавляющем большинстве случаев устройства используют прямоугольную систему координат, которую называют Декартовой. Устройства использующие полярную систему координат встречаются очень редко и большинство читателей никогда с ними не столкнется.

Линия в Декартовой системе координат является функциональной зависимостью между двумя переменными X и Y, которые соответствуют координатным осям. В аналитической геометрии линия на плоскости определяется так

  • Линией на плоскости называют геометрическое место точек M(x;y), координаты которых удовлетворяют уравнению F(x,y)=0, где F(x,y) – многочлен степени n.

Мы сегодня рассматриваем прямые линии, поэтому степень многочлена равна 1. Уравнение прямой линии на плоскости можно записать в различных вариантах, но все они являются лишь вариантами общего уравнения прямой

Общее уравнение. Иллюстрация моя
Общее уравнение. Иллюстрация моя

Оба коэффициента, А и В, никогда не равны 0 одновременно. Это важное условие. Если оба коэффициента отличны от 0, то тоже самое уравнение можно записать в и в таком виде

Уравнение прямой в отрезках. Иллюстрация моя
Уравнение прямой в отрезках. Иллюстрация моя

Такая форма записи называется уравнением прямой в отрезках. И, наконец, самое привычное большинству уравнение прямой, которое называется уравнением прямой с угловым коэффициентом

Самое привычное уравнение прямой с угловым коэффициентом. Иллюстрация моя
Самое привычное уравнение прямой с угловым коэффициентом. Иллюстрация моя

Однако, нам требуется не просто уравнение прямой линии, нам требуется уравнение с наложением дополнительных условий. Чаще всего, прямая линия задается двумя точками, лежащими на этой прямой. Точки одновременно являются и концами отрезка прямой, который нужно нарисовать. В конечном итоге, размеры любого устройства вывода, любого чертежа, ограничены. Поэтому мы всегда используем именно отрезки прямых, а не собственно прямыми. Значит, нам потребуется и уравнение прямой проходящей через две заданные точки

Уравнение (в координатном виде) прямой проходящей через две заданные точки. Иллюстрация моя
Уравнение (в координатном виде) прямой проходящей через две заданные точки. Иллюстрация моя

Для отрезка прямой заданные точки Р1 и Р2 одновременно задают и границы диапазонов изменения координат. Но и это уравнение всего лишь одна из форм записи общего уравнения прямой.

Обратите внимание, в этом уравнении мы видим две разности, стоящие в знаменателях. По сути, эти разности являются длинами отрезков, которые являются проекциями отрезка прямой на оси координат. Мы можем записать

Δx = x2 - x1

Δy = y2 - y1

Это нам скоро понадобится, так как мы переходим от математики абстрактной к рассмотрению работы алгоритма Брезенхема.

Проблемы с растровым изображением прямой

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

Дело в том, что вычисления с использованием чисел с плавающей запятой гораздо более медленные, чем вычисления с целыми числами. И не каждый процессор имеет команды работы с вещественными числами. Да, современный настольный ПК достаточно быстр и умеет работать с числами вещественными числами в формате плавающей запятой. Но что если нужно нарисовать очень много отрезков прямых?

Сегодня видеокарты ПК умеют на аппаратном уровне выполнять отображение базовых графических примитивов, но так было не всегда. Не так давно все операции выполнялись центральным процессором и требовали доступа к видеопамяти для отображения каждой точки (пикселя). А доступ к видеопамяти гораздо медленнее, чем доступ к оперативной памяти.

Кроме того, кроме ПК и достаточно мощных микропроцессоров есть и микроконтроллеры, к которым тоже подключают графические дисплеи. Значит, нужно использовать целые, а не вещественные числа. И как то оптимизировать доступ к видеопамяти. Второе немного сложнее, а вот в вычислениях "тот кто нам мешает, нам поможет", как говорится в одном известном фильме.

Второй проблемой является то, что точная прямая не проходит точно через каждую допустимую точку растрового изображения

Точная прямая не может быть точно отображена в растровом виде. Иллюстрация моя
Точная прямая не может быть точно отображена в растровом виде. Иллюстрация моя

Тонкие серые линии соответствуют координатной сетке пикселей. Сами пиксели, точки-элементы растрового изображения, располагаются только на пересечении этих координатных линий. Что и показано на иллюстрации. Наш отрезок прямой начинается и заканчивается точно в координатах пикселей. Но вот остальные точки прямой... Мы не можем поставить точку, включить пиксел, если прямая не проходит точно через его месторасположения. И таких точек, не считая точек начала и конца отрезка, нашлось всего две.

Согласитесь, если стереть изображение точной прямой, то оставшиеся 4 точки будут мало похожи на отрезок прямой. Что бы это исправить, нужно нарисовать дополнительные точки для каждого пикселя лежащего ближе к отрезку по всей его длине. Результат будет примерно таким

Результат растеризации нашего отрезка прямой. Иллюстрация моя
Результат растеризации нашего отрезка прямой. Иллюстрация моя

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

Но почему две точки на иллюстрации красного цвета? Все дело в том, что точная прямая проходит ровно по середине между двумя пикселями по вертикали. А значит, можно выбрать любую из двух точек, какая вам, или вашему алгоритму, больше нравится.

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

Эти проблемы решает, не всегда безусловно удачно, алгоритм предложенный Дж. Э. Брезенхемом еще в 1965 году.

Принцип работы алгоритма Брезенхема

Для начала, давайте рассмотрим отрезок прямой, начальная точка которого располагается в центре координат, то есть, координаты начала (0, 0). Для упрощения. Перенести начало координат в любую точку не так сложно. Кроме того, угол между отрезком прямой и осью Х будет лежать в диапазоне от 0 до 45 градусов.

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

Осталась еще одна проблема, которая не столь остра сегодня, но была серьезной во времена, когда алгоритм разрабатывался. Эта проблема заключается в использовании умножения/деления при вычислении значения координаты Y для очередного значения координаты X. Команды умножение есть не во всех процессорах (каждый микроконтроллер имеет внутри себя процессор). Команды деления встречаются еще реже. Поэтому умножение и деление могут выполняться не аппаратно, а программно, бит за битом. И это гораздо медленнее. Но даже если есть аппаратные команды, они часто выполняются медленнее команд сложения/вычитания.

Вычисление координат пикселей выполняется в самом внутреннем цикле программы рисования отрезков прямых и выполняется много раз. Поэтому даже незначительное изменение скорости его выполнения оказывает в результате большое влияние. Поэтому от умножения, тем более, деления, нужно отказываться. Для этого Брезенхем перешел от работы с координатами и уравнением прямо к работе с приращениями координат.

Для начала давайте немного преобразуем уравнение прямой проходящей через две заданные точки, для нашего случая

Рассматриваемый Брезенхемом случай отрезка прямой. Иллюстрация моя
Рассматриваемый Брезенхемом случай отрезка прямой. Иллюстрация моя

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

При этом во время каждой итерации цикла нам нужно решить, в какой из двух соседних по вертикали пикселей ставить точку. Давайте рассмотрим это немного подробнее

Выбор одного из двух пикселей по вертикали в алгоритме Брезенхема. Иллюстрация моя
Выбор одного из двух пикселей по вертикали в алгоритме Брезенхема. Иллюстрация моя

На иллюстрации показана черная точка, с которой мы работали на предыдущей итерации цикла рисования. Две возможные точки, A и B, одну из которых нам и нужно выбрать на текущей итерации, показаны красным цветом. Показаны и расстояния от точной прямой до возможных точек, они обозначены прописными буквами a и b.

На самом деле, здесь нет ничего сложного. Все решает простое сравнение

  • Если a < b, то выбирается пиксель A
  • В противном случае выбирается пиксель B

При равенстве расстояний, в данном варианте алгоритма, выбирается пиксель B. Это исключает неопределенность. Впрочем, вы можете предпочесть выбор A, я уже говорил, что это дело личных предпочтений, в данном случае, программиста.

Радует, что выбор одного из пикселей не требует сложных медленных операций. Правда пока не понятно, как вычислять a и b. Для того, что бы разобраться с этим, придется еще немного позаниматься математикой. И для начала, поскольку алгоритм работает с приращениями, заменим Δx на dx, а Δy на dy. Это чисто косметическая замена, но она отражает суть. Ведь приращения используются на каждой шаге алгоритма, каждой итерации цикла. Мы работаем с приращением между итерациями.

И мы можем записать формулы для расстояний a и b

Вычисление расстояний a и b. Иллюстрация моя
Вычисление расстояний a и b. Иллюстрация моя

Может возникнуть вопрос, откуда взялось +1 в формуле для a, ведь в формуле для b этого нет? Все просто. Координата Y точки B равна координате Y точки на предыдущем шаге, это видно на иллюстрации. А вот координата точки Y на единицу больше.

Внимательный, ни нетерпеливый, читатель может воскликнуть "да ведь все стало гораздо сложнее!". И будет прав, с точки зрения вида математических формул. Но будет ошибаться, с точки зрения программной реализации этих вычислений. И скоро это будет очень хорошо видно.

Давайте будем сравнивать вычисленные по этим формулам числа не "в лоб", а а через нахождение их разности. С точки зрения внешнего вида формул все станет еще сложнее, но вы же помните "что нам мешает, то нам и поможет". Воспользуемся нашим упрощением "угол наклона лежит в диапазоне от 0 до 45 градусов". Это значит, что у нас x2 всегда больше x1 и dx всегда больше 0. И мы можем записать

Математические преобразования для вычисления разности вместо сравнения двух чисел. Иллюстрация моя
Математические преобразования для вычисления разности вместо сравнения двух чисел. Иллюстрация моя

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

Дальнейшие преобразования дают "неожиданное" упрощение. Иллюстрация моя
Дальнейшие преобразования дают "неожиданное" упрощение. Иллюстрация моя

Это просто магия математики, и ничего больше. Да, я опустил подробные пояснения и промежуточные преобразования, оставил только самые важные. Любой читатель может проделать полные преобразования самостоятельно. Тут нет ничего сложного. Но теперь хорошо видно, что все "страшные" вычисления, которые у нас были в процессе преобразований, привели к довольно простому результату.

Во первых, наши вычисления во многом сводятся к работе с приращениями координат между двумя последовательными итерациями алгоритма. Причем приращение координаты X всегда равно 1, я даже выделил это красным цветом. Приращение координаты Y равно или 1, если выбирается пиксель A, или равно 0, если выбирается пиксель B.

Начальная точка отрезка не имеет предыдущей точки. Поэтому мы просто задаем для нее

  • di = 2 dy - dx

Как вычисляются dx и dy мы уже знаем, это разность между соответствующими координатами конечной и начальной точек. А дальше, уже на первой итерации цикла, эта di становится предыдущей точкой. И наши действия будут очень простыми. Напомню, что мы пока работаем с отрезками в первом квадранте декартовой системы координат.

Подготовительные шаги довольно просты и очевидны. Причем эти шаги выполняются только один раз для каждого рисуемого отрезка прямой.

В Дзен так и не появилось какого либо способа размещать преформатированный текст. Поэтому придется пользоваться картинками. Уж извините

Я буду использовать псевдоязык программирования. Скорее даже не программирования, а публикации алгоритмов.

-13

Далее пойдет основной цикл алгоритма, причем в нем будут выполняться только просты действия. Ничего лишнего. Все максимально быстро

-14

И это все! Вот во что превратились все кажущиеся сложными математические преобразования и формулы.

Давайте теперь посмотрим на все это с немного другой стороны. Во первых, от di нам нужен только знак для принятия решения о выборе одного из двух пикселей. Именно знак di определяет, какое из двух расстояний больше. Поэтому мы используем сравнение с 0, которое в большинстве процессоров выполняется быстро.

Величина приращения координаты X всегда равна 1, мы это уже видели, так как нам нужно обработать все пиксели отрезка. Величина приращения координаты Y равна или 0, или 1. В зависимости от того, какую точку мы выбрали. С приращение di все немного интереснее. Это приращение нам нужно для корректной работы алгоритма (в соответствии с нашими формулами). И у нас может быть два возможных приращения, но мы их оба можем вычислить до основного цикла, во время предварительных шагов. Что мы и сделали. И в цикле остается просто операция сложения. Она есть всегда и выполняется быстро на любом процессоре.

Кстати, мы и от операции умножения избавились в процессе всех математических преобразований! Умножение на 2 можно заменить на сдвиг влево. Но это уже совсем другая история. Погружаться в тонкости машинных команд и представления данных мы сегодня не будем. Если вам интересно, можете почитать

Общий случай рисования отрезков с помощью алгоритма Брезенхема

Мы разобрались, как этот алгоритм работает, но установили некоторые ограничения и упрощения. Давайте попробуем от них избавиться. И начнем мы с угла между отрезком и осью Х. Но пока будем оставаться в первом квадранте.

Почему мы установили ограничение в 45 градусов? Дело в том, что если угол больше 45 градусов, то у нас будет dx<dy. 45 градусов это просто граничный случай, когда они равны. Если dx<dy, то то на отрезке появятся участки параллельные оси Y, а не оси X, как мы рассматривали ранее. Наш вариант алгоритма будет это случай отрабатывать некорректно, ведь каждому значению координаты X теперь могут соответствовать несколько точек.

Проблема решается, а ограничение снимается, довольно просто. Вместо цикла по X нужно выполнять цикл по Y.

Второе ограничение. Что будет, если координата Y точки конца отрезка будет меньше координаты Y начала? Тут все еще проще. У нас просто приращение y будет равно не +1, а -1. И мы можем учесть это введя дополнительную переменную и установив ее значение на предварительном этапе, до основного цикла.

Третье, последнее ограничение, связано с возможность расположения отрезка во втором и третьем квадрантах. И снова ничего сложного, мы просто меняем местами точки начала и конца. И сделать это можно до основного цикла.

Алгоритм, на самом деле, универсален. Просто иногда нужно сделать дополнительные предварительные шаги. Я не буду приводить полную версию алгоритма. Во первых, почти все варианты мы уже рассмотрели и там нет ничего сложного. Во вторых, есть много готовых текстов программ, которые реализуют алгоритм Брезенхема для разных комбинаций процессор - устройство вывода. И теперь вы вполне сможете разобраться, как же они работают. Мы действительно рассмотрели все важные моменты.

Оптимизация

Увы, все не так просто, если взять реальные устройства вывода. Нет, алгоритм работает отлично, все быстро, только вот количество обращений к видеопамяти велико. Те самые вызовы PixelON, которые могут еще и цвет пикселя задавать. Это очень медленные операции. Проблема заключается в том, что оптимизация обращений к видеопамяти сильно зависит от того, с каким именно устройством вывода мы работаем. Поэтому, и очень кратко, рассмотрим лишь пару вариантов.

Во первых, пиксели, если говорить о растровых графических дисплеях, часто бывают организованы в группы по 8, 16, и т.д. То есть, изменяя состояние одного пикселя мы, фактически, выполняем операцию над группой пикселей. Поэтому можно отслеживать, что изменение адреса пикселя соответствующее координате X находится в пределах одной группы. И не обращаться к видеопамяти пока мы не выходим за ее пределы. Таким образом, если пиксели сгруппированы по 8 (байт) мы можем в 8 раз снизить количество обращений к медленной видеопамяти.

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

Стоит ли получаемый выигрыш в скорости заметного усложнения программы? Зависит от многих факторов, тут нет однозначного ответа. Но в достаточном количестве случаев это имеет смысл.

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

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

Другой способ оптимизации связан с тем, что графический дисплей может иметь несколько страниц памяти, каждая из которых соответствует полноценному графическому экрану. При этом доступ к странице, которая в данный момент отображается, будет медленным. А к неактивным страницам гораздо более быстрым. И мы можем сформировать нужное изображение на неактивной странице, а потом просто переключить на нее отображение.

Заключение

Алгоритм Брезенхема придуман давно, в те времена, когда машинная графика еще только начинала появляться. И он учитывает реалии тех лет. По сути, это просто небольшое математическое упражнение, которое позволяет ускорить и упростить рисование прямых линий. Но он сохраняет актуальность и сегодня, пусть область применения его программных реализаций и сузилась, уступив место реализациям аппаратным.

Тема машинной графики сложна не только тем, что требует, иногда значительного, объема математики. В конечном итоге, математика не так страшна. Но графика очень сильно зависит от конкретного оборудования, и это гораздо более сложный вопрос. Если конечно не подходить к машинной графике с точки зрения простого пользователя пакета графических подпрограмм.

Но ведь кто-то эти пакеты подпрограмм и разрабатывает... И теперь вы немного узнали, "что там у куколки внутри".

До новых встреч!