Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
20071227_Chumak_MU.doc
Скачиваний:
4
Добавлен:
09.11.2019
Размер:
694.27 Кб
Скачать

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 XleftXe ≤Xright перевiряємо рядки, що розташованi безпосередньо над i пiд рядком, що сканується. Визначаємо, є на цих рядках пiкселi (тобто, не всi пiкселi є граничними, або вже є заповненими). Якщо такi пiкселi ще є, то для кожного неперервного iнтервалу з цих рядкiв у дiапазонi XleftXe ≤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].

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]