Глава 4. Алгоритмы растровой графики  

Глава 4. Алгоритмы растровой графики

Рисование отрезков прямых


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

Термин “пиксел” образован от английского pixel (picture element - элемент изображения) - то есть точка на экране. Будем считать, что пикселы имеют целочисленные координаты. На первый взгляд кажется, что эта задача имеет простое решение. Пусть конечные точки отрезка имеют целочисленные координаты, и уравнение прямой, содержащей отрезок: . Не нарушая общности, будем также считать, что тангенс угла наклона прямой лежит в пределах от 0 до 1. Тогда для изображения отрезка на растре достаточно для всех целых , принадлежащих отрезку, выводить на экран точки с координатами . Однако в этом методе присутствует операция умножения . Хотелось бы иметь алгоритм без частого использования операции умножения вещественных чисел. Избавиться от операции умножения можно следующим образом. Поскольку , то один шаг по целочисленной сетке на оси будет соответствовать . Отсюда получаем, что будет увеличиваться на величину . Итерационная последовательность выглядит следующим образом:

,

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

операции с вещественными числами, в том числе операции умножения и деления.

Для вывода формул алгоритма Брезенхема рассмотрим рис. 30.

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

, ,

.

Поскольку знак совпадает со знаком разности , то будем проверять знак выражения . Так как и , то .

Пусть на предыдущем шаге , тогда и . Если же на предыдущем шаге , то и .

Осталось узнать, как вычислить . Так как при :

, .

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

Procedure Bresenham(x1,y1,x2,y2,Color: integer);

var

dx,dy,incr1,incr2,d,x,y,xend: integer;

begin

dx:= ABS(x2-x1);

dy:= Abs(y2-y1);

d:=2*dy-dx; {начальное значение для d}

incr1:=2*dy; {приращение для d<0}

incr2:=2*(dy-dx); {приращение для d>=0}

if x1>x2 then {начинаем с точки с меньшим знач. x}

begin

x:=x2;

y:=y2;

xend:=x1;

end

else

begin

x:=x1;

y:=y1;

xend:=x2;

end;

PutPixel(x,y,Color); {первая точка отрезка}

While x

begin

x:=x+1;

if d<0 then

d:=d+incr1 {выбираем нижнюю точку}

else

begin

y:=y+1;

d:=d+incr2; {выбираем верхнюю точку, y-возрастает}

end;

PutPixel(x,y,Color);

end;{while}

end;{procedure}

Отсечение

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

.

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

Рассмотрим алгоритм Коэна-Сазерленда для отсечения отрезков прямых. Этот алгоритм позволяет легко определять нахождение отрезка полностью внутри или полностью снаружи окна, и если так, то его можно рисовать или не рисовать, не заботясь об отсечении по границе окна.

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

Окну соответствует область обозначенная кодом 0000. Конечным точкам отрезка приписывается 4-битный код “вне/внутри” в зависимости от нахождения отрезка в соответствующей подобласти. Каждому биту присваивается значение 1 в соответствии со следующим правилом.

Бит 1 - точка находится выше окна;

Бит 2 – точка находится ниже окна;

Бит 3 - точка находится справа от окна;

Бит 4 - точка находится слева от окна;

Иначе биту присваивается нулевое значение. Значения этих битов для конечных точек отрезков легко определить по знакам соответствующих разностей: - для 1-го бита, - для 2-го бита, - для 3-го бита и - для 4-го бита. Отрезок рисуется без отсечения, то есть принимается целиком, если оба кода равны 0000, или ИЛИ , где ИЛИ – бинарная операция. Отрезок отбрасывается без вычислений если оба его конца находятся выше, ниже, правее или левее окна. В этих случаях соответствующие биты в обоих кодах равны 1 и это легко определить, умножив эти коды по бинарной операции И. Если результат операции И равен 0000, то отрезок нельзя ни принять ни отбросить, так как он может пересекаться с окном. В этом случае применяется последовательное разделение отрезка, так что на каждом шаге конечная точка отрезка с ненулевым кодом вне/внутри заменяется на точку, лежащую на стороне окна или на прямой содержащей сторону. При этом порядок перебора сторон окна не имеет значения.

Далее приводится текст процедуры на языке Паскаль, с довольно изящной реализацией этого метода. Отрезок задан граничными точками , , границы окна: xmin, xmax, ymin, ymax. Используются вызовы процедур: Accept_Check – выполняет проверку на полное принятие отрезка; Reject_Check – на полный отказ от рисования отрезка; Outcodes – вычисляет 4-х битовый код “вне/внутри”; SWAP – меняет местами координаты двух точек.

Procedure CLIP(x1,x2,y1,y2,xmin,xmax,ymin,ymax: real);

type

outcode = array[1..4] of boolean;

var

accept,reject,done: boolean;

outcode1,outcode2,

outcode3,outcode4:outcode;{коды вне/внутри}

begin

accept:= false;

reject:= false;

done:= false;

repeat

Outcodes(x1,y1,outcode1);

Outcodes(x2,y2,outcode2);

{проверка на отбрасывание}

reject:=Reject_Check(outcode1,outcode2);

if reject then done:= true

else

begin {возможно принятие целиком}

accept:=Accept_Check(outcode1,outcode2);

if accept then done:=true

else

begin {разделить отрезок}

{если P1 внутри, то с помощью SWAP сделать снаружи}

if not((outcode1[1])or(outcode1[2])or

(outcode1[3])or(outcode1[4])) then SWAP;

{теперь P1 перемещается в точку пересечения}

if outcode1[1] then

begin {отбросить верхнюю часть}

x1:=x1+(x2-x1)*(ymax-y1)/(y2-y1);

y1:=ymax;

end

else if outcode1[2] then

if outcode1[1] then

begin {отбросить нижнюю часть}

x1:=x1+(x2-x1)*(ymin-y1)/(y2-y1);

y1:=ymin;

end

else if outcode1[3] then

begin {отбросить правую часть}

y1:=x1+(y2-y1)*(ymax-x1)/(x2-x1);

x1:=xmax;

end

else if outcode1[4] then

begin {отбросить левую часть}

y1:=x1+(y2-y1)*(ymin-x1)/(x2-x1);

x1:=xmin;

end;

end;

end;

until done;

if accept then

Line(x1,y1,x2,y2); {нарисовать отрезок}

end;{procedure}


8387286434596004.html
8387317664886689.html

8387286434596004.html
8387317664886689.html
    PR.RU™