- •Київ кнутд 2007
- •1.2 Сфери використання
- •1.3 Головнi поняття I операцiї
- •1.4 Типи графiчних приладiв
- •2 Алгоритми растрової графiки
- •2.1 Растрова I векторна графiка
- •2.1.1 Цифровий диференцiйний аналiзатор
- •2.1.2 Алгоритм Брезенхема побудови вiдрiзкiв
- •2.1.3 Алгоритм Брезенхема креслення кола
- •2.1.4 Алгоритм Брезенхема побудови елiпса
- •2.2 Растрова розгортка багатокутникiв.
- •2.2.1 Алгоритм заповнення з упорядкованими списками ребер
- •2.2.2 Алгоритм заповнення за ребрами
- •2.2.3 Алгоритм заповнення iз списком ребер I прапорцем
- •2.2.4 Простий алгоритм заповнення iз зачiпкою
- •2.2.5 Алгоритм заповнення по рядкам iз зачiпкою
- •2.3 Ефект драбини
- •3. Лабораторнi роботи
- •3.1 Лабораторна робота BresLine на тему "Виведення вiдрiзкiв прямих за алгоритмом Брезенхема"
- •3.2 Лабораторна робота BresCirc на тему "Виведення дуг кола за алгоритмом Брезенхема".
- •3.3 Лабораторна робота BresEllips на тему "Виведення елiпсiв за алгоритмом Брезенхема".
- •3.4 Лабораторна робота FloodLine на тему "Заповнення полiгональних фiгур".
- •3.5 Лабораторна робота FloodCirc на тему "Заповнення довiльних областей".
- •4. Література
- •1 Вступ 5
- •2 Алгоритми растрової графiки 8
- •4. Література 54
2.2.5 Алгоритм заповнення по рядкам iз зачiпкою
У попередньому алгоритмi стек може бути досить великим, що веде до уповiльнення роботи програми. Ще один недолiк вказаного алгоритму -- у стек часто заносимо дублюючу iнформацiю, що веде до наявностi "холостого ходу". Тому iснує модифiкацiя простого алгоритму заповнення з зачiпкою - алгоритм заповнення за рядками iз зачiпкою. У модифiкованому алгоритмi розмiр стека мiнiмiзується завдяки зберiганню лише одного пiкселя iз зачiпкою для будь-якого неперервного iнтервалу на рядку, що сканується. Даний алгоритм можна використовувати до гранично-визначених областей. Гранично-визначена 4-звязна область може мiстити дiрки. В областi, що є зовнiшня до гранично-визначеної областi, яку ми розглядаємо, не повинно бути пiкселiв, колiр яких спiвпадає з кольором заливки.
Алгоритм заповнення за рядками iз зачiпкою має наступнi етапи:
1. Покласти пiксел зачiпки у стек.
2. Доки стек не є порожнiм:
а) Вибрати пiксел iз стека. Розглядати його як поточний пiксел.
в) Надати пiкселу потрiбне значення.
с) Заповнити (тобто вiдмiтити пiкселi) iнтервал, що мiстить зачiпку, лiворуч i праворуч вiд зачiпки доти, доки не буде досягнута границя. У змiнних Xleft i Xright запам'ятати крайнi пiкселi iнтервалу.
d) У дiапазонi Xleft ≤ Xe ≤Xright перевiряємо рядки, що розташованi безпосередньо над i пiд рядком, що сканується. Визначаємо, є на цих рядках пiкселi (тобто, не всi пiкселi є граничними, або вже є заповненими). Якщо такi пiкселi ще є, то для кожного неперервного iнтервалу з цих рядкiв у дiапазонi Xleft ≤ Xe ≤Xright до стеку заносимо кожен крайнiй правий пiксел (як можливий пiксел зачiпки).
При iнiцiалiзацiї алгоритму до стека заносимо початковий пiксел зачiпки, робота алгоритму закiнчується тодi, коли у стеку вже не буде пiкселiв.
Програмна реалiзацiя алгоритму заповнення за рядками iз зачiпкою.
unit LineSeedUnit1;
interface {LineSeedUnit1}
uses Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
const
_N = 1000; {максимальне число граничних пiкселiв}
_Xmax = 12; {розмiр екрану по осi абсцис}
_Ymax = 10; {розмiр екрану по осi ординат}
_Nstack = 2000;{максимальна величина стека}
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TPoint2 = array[1..2] of integer; {точка}
Border = array[1.._N] of TPoint2; {границя}
Pi = array[0.._Xmax,0.._Ymax] of boolean;{пiкселi}
tStack = array[1.._Nstack] of TPoint2; {стек пiкселiв}
Var
Form1: TForm1;
YesInput:boolean;
NP, {число граничних пикселiв}
NS, {число пiкселiв у стецi}
Xmax,Ymax, {максимальне число пiкселiв уздовж осей}
i {робоча змiнна}
: integer;
Ptemp, {поточний пiксел}
Zatr {пiксел зачiпки}
: Tpoint2;
P: Border; {список граничних пiкселiв}
Stack: tStack; {стек для пiкселiв}
M: Pi; {масив пiкселiв екрану}
fin: TextFile; {файл з вхiдними даними}
implementation {$R *.DFM}
// встановлення списку граничних пiкселiв}
procedure SetP(var P:Border;var NP:integer;var Zatr:TPoint2);
var xs,ys,xf,yf,dx,dy:integer;
begin {SetP}
assignFile(fin,'LineSeed.dat');
reset(fin); NP:=0;
readln(fin,Zatr[1],Zatr[2]);
while (not Eof(fin)) do
begin {while not Eof(fin)}
// читання наступного граничного вiдрiзку
readln(fin,xs,ys,xf,yf);
// встановлення приросту по х
if xs<xf then dx:=1;
if xs=xf then dx:=0;
if xs>xf then dx:=-1;
// встановлення приросту по y
if ys<yf then dy:=1;
if ys=yf then dy:=0;
if ys>yf then dy:=-1;
if (NP<1)or((P[NP,1]<>xs)or(P[NP,2]<>ys))
{якщо стартовий пiксел ще не занесено}
then begin
NP:=NP+1;
P[NP,1]:=xs;P[NP,2]:=ys;
end;
// занесення iнших пiкселiв до кiнцевого включно
while ((P[NP,1]<>xf)or(P[NP,2]<>yf)) do
begin
NP:=NP+1;P[NP,1]:=P[NP-1,1]+dx;
P[NP,2]:=P[NP-1,2]+dy;
end;
end; {while not Eof(fin)}
close(fin);
end; {SetP}
// гасiння пiкселiв екрану i уставлення граничних пiкселiв
procedure SetStartM(var M:Pi; Xmax,Ymax:integer;P:Border;NP:integer);
var i,j:integer;
begin {SetStartM}
for i:=0 to Xmax do
for j:=0 to Ymax do M[i,j]:=false;
for i:=1 to NP do begin
M[P[i,1],P[i,2]]:=true;
end;
end; {SetStartM}
// iнвертування пiксела
procedure Inv(var M:Pi;i,j:integer);
begin
if M[i,j]=true then M[i,j]:=false
else M[i,j]:=true;
end;
// помiщення пиксела у стек
procedure PushPixel(P:TPoint2;var s:tStack;var Ns:integer);
begin {PushPixel}
if Ns<_N then begin
Ns:=Ns+1; s[Ns,1]:=p[1];s[Ns,2]:=p[2];
end
else begin
Application.MessageBox('Багато точок у стеку',
'Переповнення стеку', MB_OK);
end;
end; {PushPixel}
// видобування пиксела iз стека
procedure PopPixel(s:tStack;var Ns:integer;var p:TPoint2);
begin {PopPixel}
if Ns>0
then begin
p[1]:=s[Ns,1];p[2]:=s[Ns,2];Ns:=Ns-1;
end;
end; {PopPixel}
function YesMarked(Ptemp:TPoint2;M:Pi):boolean;
begin {YesMarked}
if M[Ptemp[1],Ptemp[2]]=true
then YesMarked:=true
else YesMarked:=false;
end;{YesMarked}
function Mark(Ptemp:TPoint2;var M:Pi):boolean;
var PS1,PS2:PChar;
begin {Mark}
if (Ptemp[1]>=0) and (Ptemp[2]<=_Xmax) and
(Ptemp[2]>=0) and (Ptemp[2]<=_Ymax)
then begin
M[Ptemp[1],Ptemp[2]]:=true;
end
else begin
PS1:=PChar(IntToStr(Ptemp[1]));
PS2:=PChar(IntToStr(Ptemp[2]));
Application.MessageBox(PS1,PS2,MB_OK);
end;
end; {Mark}
function YesBody(Pnext:TPoint2;P:Border;NP:integer):boolean;
var i:integer;
begin {YesBody}
YesBody:=false;
for i:=1 to NP do
if (Pnext[1]=P[i,1])and(Pnext[2]=P[i,2]) then YesBody:=true;
end; {YesBody}
// лiнiйне заповнення
procedure ZapolnLin(var M:Pi;Xmax,Ymax:integer;
P:Border;NP:integer;Zatr:TPoint2);
var
i,j, {робочi змiннi}
X, {поточний пiксел}
Xright,XLeft {границi поточного рядка}
: integer;
Ptemp, {поточний пiксел}
PtempUpBack,PtempUp, {пiкселi "зверху" до стеку}
PtempDownBack,PtempDown {пiкселi "знизу" до стеку}
: TPoint2;
begin {Zapolnlin}
// заносимо пiксел зачiпки до стеку
PushPixel(Zatr,Stack,NS);
while NS<>0 do {доки стек не стане пустим}
begin {while NS<>0}
// пiксел iз стеку
PopPixel(Stack,NS,Zatr); Ptemp:=Zatr;
Mark(Ptemp,M);{вiдмiтка нового значення}
// заповнення iнтервалу справа вiд зачiпки
Ptemp[1]:=Ptemp[1]+1;
while not YesBody(Ptemp,P,NP) do
begin {while not YesBody(Ptemp,P,NP)}
Mark(Ptemp,M);{вiдмiтка нового значення}
Ptemp[1]:=Ptemp[1]+1;
end; {while not YesBody(Ptemp,P,NP)}
XRight:=Ptemp[1]-1; {крайнiй справа пiксел}
Ptemp[1]:=Zatr[1]; {х-координата зачiпки}
// заповнення iнтервалу злiва вiд зачiпки
Ptemp[1]:=Ptemp[1]-1;
while not YesBody(Ptemp,P,NP) do
begin
Mark(Ptemp,M);{вiдмiтка нового значення}
Ptemp[1]:=Ptemp[1]-1;
end;
XLeft:=Ptemp[1]+1;{крайнiй злiва пiксел}
X:=Xleft; PtempUp[2]:=Zatr[2]+1;
PtempDown[2]:=Zatr[2]-1;
while X<=XRight do
begin {while X<=XRight}
PtempUp[1]:=X;PtempDown[1]:=X;
PtempUpBack[1]:=PtempUp[1]-1;
PtempUpBack[2]:=PtempUp[2];
PtempDownBack[1]:=PtempDown[1]-1;
PtempDownBack[2]:=PtempDown[2];
// пошук зачiпки на рядку, що вище
// початку перегляду
if (X=Xleft)and(not YesBody(PtempUp,P,NP))and
(not YesMarked(PtempUp,M))
then begin {X=Xleft}
PushPixel(PtempUp,Stack,NS);
end; {X=Xleft}
// при поточному переглядi
if (X>Xleft)and(not YesBody(PtempUp,P,NP))and
(not YesMarked(PtempUp,M))and
(YesBody(PtempUpBack,P,NP))
then begin
PushPixel(PtempUp,Stack,NS);
X:=X+1;
end;
// пошук зачiпки на рядку, що нижче
// початку перегляду
if (X=Xleft)and(not YesBody(PtempDown,P,NP))and
(not YesMarked(PtempDown,M))
then PushPixel(PtempDown,Stack,NS);
// при поточному переглядi
if (X>Xleft)and(not YesBody(PtempDown,P,NP))and
(not YesMarked(PtempDown,M))and
(YesBody(PtempDownBack,P,NP))
then PushPixel(PtempDown,Stack,NS);
X:=X+1;
end; {while X<=XRight}
end;{while NS<>0}
// виведення вiдмiчених пiкселiв
for j:=Ymax downto 0 do
for i:=0 to Xmax do
begin {for j,i}
if M[i,j]=true
then Form1.Canvas.Pixels[i,j]:=clRed
else Form1.Canvas.Pixels[i,j]:=clWhite;
end; {Zapolnlin}
// кнопка "Багатокутник"
procedure TForm1.Button1Click(Sender: TObject);
begin {TForm1.Button1Click}
if not YesInput
then begin
YesInput:=true;
Button1.Visible:=false; Button2.Visible:=true;
SetP(P,NP,Zatr); {уставлення списку граничних пiкселiв}
NS:=0; {"звiльнення стеку"}
SetStartM(M,Xmax,Ymax,P,NP);{уст.граничних пiкселiв}
end;
end; {TForm1.Button1Click}
// кнопка "Заповнення"
procedure TForm1.Button2Click(Sender: TObject);
begin {TForm1.Button2Click}
if YesInput then
begin
Zapolnlin( M,Xmax,Ymax,P,NP,Zatr);
End;
end; {TForm1.Button2Click}
end. {LineSeedUnit1}
Лiтература.[5, стор. 114-119].