Простой "квадратный" фрактал
Простой "квадратный" фрактал - частный случай фракталов из многоугольников. Конечная картинка представляет собой совокупность квадратов с уменьшающимеся размерами. Центр каждого квадрата является вершиной какого-то квадрата. Основная задача состоит в том, чтобы избежать построения квадратов, чьими центрами являются вершиный квадратов лежащие внутри уже построеных квадратов. Алгоритм: 1. Создаём структуру , которая будет содержать координаты центров квадратов (Spoint). 2. По таймеру вызывается процедура Draw. 3. В процедуре Draw происходит рисование квадратов,центр которых - это точки, параметр draw которых равен true. 4. Увеличиваем счётчик num отвечающий за количество квадратов, которые будут построены на следующем шаге. num изменяется по степеням четвёрки. 5. В цикле "while k меньше num” добавляются вершины построеных квадратов в массив точек.При этом если вершины принадлежат квадратам,которые не были нарисованы, то добавляемая точка будет иметь в параметре draw значение false. Рассмотрим значение flag.Оно изменяется от 1 до 4. Если flag=1, тогда центр построенного при данном вызове процедуры Draw квадрата - это левая верхняя вершина квадрата построенного при предыдущем вызове процедуры Draw, если flag=2 - правая верхняя, flag=3 - правая нижняя, flag=4 - левая нижняя. 6. При добавлении в массив точки, которая является ЛЕВОЙ ВЕРХНЕЙ вершиной квадрата, проверяем , построенли этот квадрат "вокруг" ПРАВОЙ НИЖНЕЙ вершины квадрата, строившегося на предыдущем шаге процедуры Draw.Если да (т.е. flag=3), то парметр draw у добавляемой точки принимает занчение false. 7. При добавлении в массив точки, которая является ПРАВОЙ ВЕРХНЕЙ вершиной квадрата, проверяем , построенли этот квадрат "вокруг" ЛЕВОЙ НИЖНЕЙ вершины квадрата, строившегося на предыдущем шаге процедуры Draw.Если да (т.е. flag=4), то парметр draw у добавляемой точки принимает занчение false. 8. При добавлении в массив точки, которая является ПРАВОЙ НИЖНЕЙ вершиной квадрата, проверяем , построенли этот квадрат "вокруг" ЛЕВОЙ ВЕРХНЕЙ вершины квадрата, строившегося на предыдущем шаге процедуры Draw.Если да (т.е. flag=1), то парметр draw у добавляемой точки принимает занчение false. 9. При добавлении в массив точки, которая является ЛЕВОЙ НИЖНЕЙ вершиной квадрата, проверяем , построенли этот квадрат "вокруг" ПРАВОЙ ВЕРХНЕЙ вершины квадрата, строившегося на предыдущем шаге процедуры Draw.Если да (т.е. flag=2), то парметр draw у добавляемой точки принимает занчение false.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,CRT,
StdCtrls, ExtCtrls;
const
Min = 1;//Минимальный размер квадрата
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
PaintBox1: TPaintBox;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Draw(Sender: TObject) ;
procedure PaintBox1DblClick(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
type Spoint = record //Структура данных для точек
x,y: Double;
draw : Boolean;
end;
var
Form1: TForm1;
size : real;
num,i,j,k,t,flag : integer;
a : array [1..66000] of Spoint; //Массив точек
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
i:=1; //Номер последней точки, "вокруг" которой был построен квадрат
j:=1; //Номер последней точки в массиве
num:=1;//Количество точек, "вокруг" которых на данном шаге будут построены квадраты
k:=1; //Счётчик количества построеных квадратов на данном шаге
t:=1; //"Указатель" на точку, которая "пораждает" новые точки (рассматриваемая точка)
flag:=0;//Особый маркер
a[1].draw:=true;
a[1].x:=320;//
//координаты первой точки массива
a[1].y:=240;//
size:=120;//Размер первого квадрата
Timer1.Enabled:=true;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
close;
end;
procedure TForm1.Draw(Sender: TObject);
begin
if Size > Min then
begin
paintbox1.Canvas.Brush.Style:=bsclear;
t:=i;
for k:=1 to num do begin //постороение квадратов "вокруг" точек
if a[i].draw=true then
paintbox1.canvas.Rectangle(Round(a[i].x - Size), Round(a[i].y - Size),Round(a[i].x + Size), Round(a[i].y + Size));
i:=i+1;
end;
num:=num*4;
j:=i;
k:=1;
while k<num do begin // добавление новых точек в массив
if flag>4 then flag:=1;
//На первом шаге в массив с точками добавляется левая верхняя вершина квадрата
a[ j ].x:= a[t].x - Size;
a[ j ].y:= a[t].y - Size;
a[ j ].draw:=true;
if a[t].draw=false then a[j].draw:=false;//если рассматриваемая точка пораждается точкой, "вокруг" которй не строился квадрат, то вокруг рассматриваемой точки также не строится квадрат (на последующих шагах повторяется данная проверка)
if flag=3 then //если рассматриваемая вершина принадлежит квадрату, который построен "вокруг" ПРАВОЙ НИЖНЕЙ вершины другого квадрата,то "вокруг" рассматриваемой точки не нужно строить квадрат
if num>4 then
a[j].draw:=false;
//На втором шаге в массив с точками добавляется правая верхняя вершина квадрата
a[j+1].x:= a[t].x + Size;
a[j+1].y:= a[t].y - Size;
a[j+1].draw:=true;
if a[t].draw=false then a[j+1].draw:=false;
if flag=4 then //если рассматриваемая вершина принадлежит квадрату, который построен "вокруг" ЛЕВОЙ НИЖНЕЙ вершины другого квадрата,то "вокруг" рассматриваемой точки не нужно строить квадрат
if num>4 then
a[j+1].draw:=false;
//На третьем шаге в массив с точками добавляется правая нижняя вершина квадрата
a[j+2].x:= a[t].x + Size;
a[j+2].y:= a[t].y + Size;
a[j+2].draw:=true;
if a[t].draw=false then a[j+2].draw:=false;
if flag=1 then //если рассматриваемая вершина принадлежит квадрату, который построен "вокруг" ЛЕВОЙ ВЕРХНЕЙ вершины другого квадрата,то "вокруг" рассматриваемой точки не нужно строить квадрат
if num>4 then
a[j+2].draw:=false;
//На четвёртом шаге в массив с точками добавляется левая нижняя вершина квадрата
a[j+3].x:= a[t].x - Size;
a[j+3].y:= a[t].y + Size;
a[j+3].draw:=true;
if a[t].draw=false then a[j+3].draw:=false;
if flag=2 then //если рассматриваемая вершина принадлежит квадрату, который построен "вокруг" ПРАВОЙ ВЕРХНЕЙ вершины другого квадрата,то "вокруг" рассматриваемой точки не нужно строить квадрат
if num>4 then
a[j+3].draw:=false;
flag:=flag+1;
k:=k+4;
j:=j+4;
t:=t+1;
end;
size := Size / 2;
end;
if Size < Min then
Timer1.Enabled:=false;
end;
procedure TForm1.PaintBox1DblClick(Sender: TObject);
begin
paintbox1.Refresh;
end;
initialization
{$I unit1.lrs}
end.
Материал позаимствован с сайта
|