35
Введение Понятия фрактал, фрактальная геометрия и фрактальная графика, появились в конце 70-х. Слово фрактал образовано от латинского fractus и в переводе означает «состоящий из фрагментов». Оно было предложено математиком Бенуа Мандельбротом в 1975 году для обозначения нерегулярных, но самоподобных структур. Рождение фрактальной геометрии принято связывать с выходом в 1977 году книги Мандельброта «The Fractal Geometry of Nature». В его работах использованы научные результаты других ученых, работавших в 1875 – 1925 годах в той же области (Пуанкаре, Фату, Жюлиа, Кантор, Хаусдорф). Но только в наше время удалось объединить их работы в единую систему. Определение фрактала, данное Мандельбротом: фракталом называется структура, состоящая из частей, которые в каком-то смысле подобны целому. Самоподобие – одно из основных свойств фракталов. Объект называют самоподобным, когда увеличенные части объекта походят на сам объект и друг на друга. Геометрические фракталы. Фракталы этого класса самые наглядные. В двухмерном случае их получают с помощью некоторой ломаной (или поверхности в трехмерном случае), называемой 1

Фракталы

  • Upload
    dasha

  • View
    8

  • Download
    2

Embed Size (px)

DESCRIPTION

Геометрические и алгебраические фракталы. Программы на языке Delphi. Примеры изображений фракталов.

Citation preview

Page 1: Фракталы

Введение

Понятия фрактал, фрактальная геометрия и фрактальная графика, появились

в конце 70-х. Слово фрактал образовано от латинского fractus и в переводе

означает «состоящий из фрагментов». Оно было предложено математиком

Бенуа Мандельбротом в 1975 году для обозначения нерегулярных, но

самоподобных структур. Рождение фрактальной геометрии принято

связывать с выходом в 1977 году книги Мандельброта «The Fractal Geometry

of Nature». В его работах использованы научные результаты других ученых,

работавших в 1875 – 1925 годах в той же области (Пуанкаре, Фату, Жюлиа,

Кантор, Хаусдорф). Но только в наше время удалось объединить их работы в

единую систему. Определение фрактала, данное Мандельбротом: фракталом

называется структура, состоящая из частей, которые в каком-то смысле

подобны целому. Самоподобие – одно из основных свойств фракталов.

Объект называют самоподобным, когда увеличенные части объекта походят

на сам объект и друг на друга.

Геометрические фракталы.

Фракталы этого класса самые наглядные. В двухмерном случае их получают

с помощью некоторой ломаной (или поверхности в трехмерном случае),

называемой генератором. За один шаг алгоритма каждый из отрезков,

составляющих ломаную, заменяется на ломаную-генератор, в

соответствующем масштабе. В результате бесконечного повторения этой

процедуры, получается геометрический фрактал.

Алгебраические фракталы.

Если геометрические фракталы встречаются в пространственно-

геометрических приложениях (длина береговой линии, капилляры

сосудистой системы), то алгебраические фракталы, или аттракторы, связаны

с процессами, протекающими во времени и кажущиеся на первый взгляд

хаотическими.

1

Page 2: Фракталы

Теория хаоса необычайно популярна в последнее время: при ближайшем

рассмотрении оказывается, что хаос несет в себе элементы

упорядоченности, но они определяются таким количеством

взаимосвязанных факторов, что «отследить» их можно только описательно, с

помощью весьма общих рассуждений. Самый характерный пример такого

хаоса – атмосферные процессы. С одной стороны, все факторы, влияющие

на погоду, известны, однако их так много и они настолько сложно

взаимосвязаны, что экстраполирование даже некоторых параметров в

настоящее время пока не поддается математикам.

2

Page 3: Фракталы

Рекурсивные алгоритмы.

Для построения фрактальных кривых используются рекурсивные алгоритмы.

Алгоритм называется рекурсивным (или рекурсией), когда он вызывает себя в

качестве вспомогательного. Рекурсивными бывают подпрограммы-процедуры и

подпрограммы-функции. В рекурсивных подпрограммах в теле процедуры или в

функции имеется вызов этих же подпрограмм. Процесс обращения к себе

самому может длиться бесконечно. Для обеспечения остановки устанавливают

барьер в виде некоторого условия.

Рекурсия – это мощный метод программирования, который позволяет делить

задачу на части все меньшего и меньшего размера до тех пор, пока они не

станут настолько малы, что решение этих подзадач сведется к набору простых

операций. Рекурсия встречается достаточно часто, но есть ситуации, когда ее

использование неуместно и даже вредно.

При работе с рекурсивными алгоритмами нужно избегать трех основных

опасностей:

1) бесконечная рекурсия. Нужно убедиться, что алгоритм имеет надежное

условие остановки;

2) глубокая рекурсия. Если алгоритм вызывает слишком глубокую рекурсию,

он исчерпает всю память стека.

3) неуместная рекурсия. Обычно это происходит, когда алгоритм, много раз

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

Рекурсия полезна при решении задач, которые могут быть разложены на

несколько подзадач. Таким образом, применение рекурсии целесообразно

при построении фрактальных кривых, так как они обладают таким свойством

как самоподобие. Алгоритмы построения фрактальных кривых рекурсивны

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

3

Page 4: Фракталы

Рекурсивное построение кривых Серпинского.

Кривые Серпинского – это самоподобные кривые, которые обычно

определяются рекурсивно. На рисунке 1.2

изображены кривые Серпинского с глубиной 1, 2 и 3.

Кривые Серпинского проще строить с помощью четырех отдельных

процедур, работающих совместно, - SierpA, SierpB, SierpC и SierpD. Эти

процедуры косвенно рекурсивные – каждая из них вызывает другие, которые

после этого вызывают первоначальную процедуру. Они выводят верхнюю,

левую, нижнюю и правую части кривой Серпинского соответственно.

На рисунке 1.3 показано, как эти процедуры образуют кривую глубины 1.

Отрезки, составляющие кривую, изображены со стрелками, которые

указывают направление их рисования. Сегменты, используемые для

соединения частей, представлены пунктирными линиями.

4

Page 5: Фракталы

Каждая из четырех основных кривых составлена из линий диагонального

сегмента, вертикального или горизонтального и еще одного диагонального

сегмента. При глубине рекурсии больше 1 необходимо разложить каждую

кривую на меньшие части. Это можно сделать, разбивая каждую их линий

диагональных сегментов на две подкривые.

Например, чтобы разбить кривую типа А, первый диагональный отрезок

делится на кривую типа А, за которой следует кривая типа В. Затем без

изменения выводиться линия горизонтального сегмента так же, как и в

исходной кривой типа А. И наконец, второй диагональный отрезок

разбивается на кривую типа D, за которой следует кривая типа А. На

рисунке 1.4 изображен процесс построения кривой 2-го порядка,

сформированной из кривых 1-го порядка. Подкривые показаны жирными

линиями.

На рисунке 1.5 показано, как из четырех кривых 1-го порядка формируется

полная кривая Серпинского 2-го порядка. Каждая из подкривых обведена

пунктирными линиями.

5

Page 6: Фракталы

С помощью стрелок типа → и ←, отображающих типы линий, которые

соединяют части кривых между собой (тонкие линии на рисунке 1.4), можно

перечислить рекурсивные зависимости между четырьмя типами кривых, как

показано на схеме ниже.

A: A B← D A

B: B C A B

C: C D → B C

D: D A C D

Код Delphi для рисования кривых Серпинского приведен ниже.

Листинг 1. Рисование кривых Серпинского.

type TCerpin = class(TForm) //имя формы – “Cerpin” procedure SierpA(depth, dist:Integer; canvas: TCanvas); procedure SierpB(depth, dist:Integer;canvas: TCanvas); procedure SierpC(depth, dist:Integer;canvas: TCanvas); procedure SierpD(depth, dist:Integer;canvas: TCanvas); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end;

VarCerpin: TCerpin;

dist: integer=7; // задаем длину отрезков линииdepth: integer; // порядок кривойimplementation{$R *.dfm}procedure TCerpin.SierpA(depth,dist: Integer;Canvas:TCanvas); // строим кривую типа Аbeginif (depth=1) then begin // строим кривую типа А первого порядкаCerpin.Canvas.Pen.Color:=clYellow; //задаем цвет для рисованияCerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+dist); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+0); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y-dist); end else begin // если порядок кривой больше 1, то составляем кривую из меньших кривых, как показано на рисунке 1.5 Cerpin.Canvas.Pen.Color:=clYellow; SierpA(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+dist);

6

Page 7: Фракталы

SierpB(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+0); SierpD(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y-dist); SierpA(depth-1,dist,canvas); end;end;

procedure TCerpin.SierpB(depth, dist: Integer;Canvas:TCanvas);beginif (depth=1) then beginCerpin.Canvas.Pen.Color:=clred; Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+dist); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+0,Cerpin.Canvas.PenPos.Y+dist);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+dist); end else beginCerpin.Canvas.Pen.Color:=clred; SierpB(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+dist); SierpC(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+0,Cerpin.Canvas.PenPos.Y+dist); SierpA(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+dist); SierpB(depth-1,dist,canvas); end;end;

procedure TCerpin.SierpC(depth, dist: Integer;Canvas:TCanvas);beginif (depth=1) then beginCerpin.Canvas.Pen.Color:=clLime;Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y-dist);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+0); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+dist); end else beginCerpin.Canvas.Pen.Color:=clLime;SierpC(depth-1,dist,canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y-dist); SierpD(depth-1,dist,canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+0); SierpB(depth-1,dist,canvas); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+dist);SierpC(depth-1,dist,canvas);end;end;

procedure TCerpin.SierpD(depth, dist: Integer;Canvas:TCanvas);beginif (depth=1) then begin Cerpin.Canvas.Pen.Color:=clTeal; Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y-dist); Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+0,Cerpin.Canvas.PenPos.Y-dist);

7

Page 8: Фракталы

Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y-dist); end else beginCerpin.Canvas.Pen.Color:=clTeal;SierpD(depth-1,dist,canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y-dist);SierpA(depth-1,dist,canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+0,Cerpin.Canvas.PenPos.Y-dist);SierpC(depth-1,dist,canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y-dist);SierpD(depth-1,dist,canvas);end;end;procedure TCerpin.FormPaint(Sender: TObject); // выводим изображение кривых Серпинского на канву формы с помощью события OnPaint.beginCerpin.Canvas.MoveTo(dist,dist);SierpB(depth,dist,Cerpin.Canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y+dist);//соединяем кривые разных типов (смотри рисунок 1.4)SierpC(depth,dist,Cerpin.Canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X+dist,Cerpin.Canvas.PenPos.Y-dist);SierpD(depth,dist,Cerpin.Canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y-dist);SierpA(depth,dist,Cerpin.Canvas);Cerpin.Canvas.LineTo(Cerpin.Canvas.PenPos.X-dist,Cerpin.Canvas.PenPos.Y+dist);end;

Примечания.

Канва – область, на которой можно рисовать чертежными инструментами –

пером, кистью и шрифтом. Канву имеют такие компоненты как, например,

форма и компонент Image. В приведенном выше листинге программы, мы

выводим изображение кривых непосредственно на форму.

Для этого мы используем событие формы OnPaint,

которое возникает при необходимости прорисовки

окна. Событие не прописывают вручную.

Поступают следующим образом, в инспекторе

объектов находят это событие и в поле, которое

находится рядом с ним, щелкают два раза мышкой.

После этого активизируется окно кода программы,

где уже будет прописана заготовка для процедуры

обработчика события OnPaint.

8

Page 9: Фракталы

9

Page 10: Фракталы

Рекурсивное построение кривых Гильберта.

Рассмотрим рекурсивное построение кривых Гильберта. На рисунке 1.6

изображены кривые Гильберта 1-го, 2-го и 3-го порядка.

Построение кривых Гильберта аналогично построению кривых Серпинского.

Ниже приведен листинг программы.

type TForm1 = class(TForm) procedure a(i:integer; canvas: Tcanvas); procedure b(i:integer; canvas: Tcanvas); procedure c(i:integer; canvas: Tcanvas); procedure d(i:integer; canvas: Tcanvas); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1; p: integer=11; u: integer=13;implementation{$R *.dfm}procedure Tform1.a(i: integer; canvas: Tcanvas);beginif i>0 then begind(i-1, canvas);canvas.LineTo(canvas.PenPos.X+u, canvas.PenPos.Y);a(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y+u);

10

Page 11: Фракталы

a(i-1, canvas);canvas.LineTo(canvas.PenPos.X-u, canvas.PenPos.Y);c(i-1,canvas);end;end;

procedure Tform1.b(i: integer; canvas: Tcanvas);beginif i>0 then beginc(i-1, canvas);canvas.LineTo(canvas.PenPos.X-u, canvas.PenPos.Y);b(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y-u);b(i-1, canvas);canvas.LineTo(canvas.PenPos.X+u, canvas.PenPos.Y);d(i-1,canvas);end;end;

procedure Tform1.c(i: integer; canvas: Tcanvas);beginif i>0 then beginb(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y-u);c(i-1, canvas);canvas.LineTo(canvas.PenPos.X-u, canvas.PenPos.Y);c(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y+u);a(i-1,canvas);end;end;

procedure Tform1.d(i: integer; canvas: Tcanvas);beginif i>0 then begina(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y+u);d(i-1, canvas);canvas.LineTo(canvas.PenPos.X+u, canvas.PenPos.Y);d(i-1, canvas);canvas.LineTo(canvas.PenPos.X, canvas.PenPos.Y-u);b(i-1,canvas);end;end;

procedure TForm1.FormPaint(Sender: TObject);beginForm1.Canvas.MoveTo(u,u);a(5,Form1.Canvas);end;end.

11

Page 12: Фракталы

Рекурсивное построение кривой «Снежинка»

Разработать программу, которая обеспечивает рисование снежинки, число

звеньев и число ветвей которой задаются пользователем.

На рисунке изображена снежинка, состоящая из трех звеньев и восьми

ветвей.

Сделаем расчет длина

каждого звена по известному значению n – количеству звеньев и величине

экрана. Будем считать, что снежинка строится в квадрате 400х400 точек. Центр

снежинки совпадает с центром квадрата, а длина отрезка каждого очередного

звена в четыре раза меньше предыдущего. Если через l обозначить длину

первого звена, то справедливо следующее равенство:

(сумма членов геометрической прогрессии)

12

Page 13: Фракталы

то есть

Пусть снежинка состоит из одного звена и р ветвей, тогда соответствующая

программа проста. Основная ее часть ее имеет вид:

for i:=1 to p dobeginx1:=trunc(x+L[k]*cos(2*pi*(i-1)/p));y1:=trunc(y+L[k]*sin(2*pi*(i-1)/p));{координаты конца очередного звена}Flake.Canvas.MoveTo(x,y); {рисование звена}Flake.Canvas.LineTo(x1,y1);End;

Здесь х, у – координаты точки центра снежинки. Снежинка должна

рисоваться как бы много раз, при этом длины звеньев изменяются, поэтому

их надо просчитать один раз и запомнить в массиве L из n элементов. Длина

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

Длина первого звена определяется из того, что в квадрате из 400х400

необходимо построить снежинку из n звеньев. Если мы дошли до этапа

рисования самого маленького звена (самой маленькой снежинки), то наша

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

Итак, логика решения задачи.

Начинаем рисовать из центра, точки А, нарисовали отрезок АВ(a), если это

не последнее звено, то будем рисовать отрезок следующего звена ВС, звено

не последнее, поэтому продолжим. Предположим, что нарисовали СЕ, это

первая часть самой маленькой снежинки, наша программа должна работать

как набросок, то есть рисовать все ветви этой снежинки. После этого мы

должны вернуться в точку В. Так как это не последняя ветвь этой снежинки,

то мы снова должны нарисовать следующую ветвь – отрезок ВД(б), а затем

снова полностью самую маленькую снежинку. Что необходимо для

реализации этой логики? Пусть значение переменной k будет равно

текущему номеру звена снежинки, в начальный момент оно равно n. Тогда

13

Page 14: Фракталы

при переходе из точек С, Д к точке В мы должны «вспомнить» координаты

точки В и номер ветви снежинки, рисуемой из точки В. При переходе от

точки В к А мы должны «вспомнить» координаты точки А и номер ветви

снежинки, рисуемой из точки А. Эта логика реализуется с помощью

рекурсии.

Листинг программы в Delphi:

type TFlake = class(TForm) //имя формы- “Flake” procedure Snow(x,y,k: Integer); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end; const p=8;var Flake: TFlake; x,y,i: integer; n: integer; L: array[1..8] of integer;implementation{$R *.dfm}procedure TFlake.Snow(x,y,k: Integer);var x1, i,y1: integer;beginif k>0 thenbeginfor i:=1 to p dobeginx1:=trunc(x+L[k]*cos(2*pi*(i-1)/p));y1:=trunc(y+L[k]*sin(2*pi*(i-1)/p));Flake.Canvas.MoveTo(x,y);Flake.Canvas.LineTo(x1,y1);snow(x1,y1,k-1); end; end;end;procedure TFlake.FormPaint(Sender: TObject);beginFlake.Canvas.Pen.Color:=clWhite;L[n]:=trunc(200*3*exp((n-1)*ln(4))/(exp(n*ln(4))-1));for i:=2 to n doL[n-i+1]:=trunc(L[n]/exp((i-1)*ln(4)));x:=300; y:=200;Snow(x,y,n);end;end.

14

Page 15: Фракталы

Рекурсивное построение треугольника Серпинского.

На рисунке 1.7 изображен треугольник Серпинского 1-го и 2-го порядка.

В треугольнике проводятся все три средние линии. В результате он

разбивается на 4 новых треугольника. К трем из них, примыкающим к

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

В Delphi это реализуется следующим образом:

type TTringle = class(TForm) Panel1: TPanel; Label3: TLabel; Label2: TLabel; Label1: TLabel; Button1: TButton; Button2: TButton; procedure Triangle(xa, ya, xb, yb, xc, yc, n: Integer); procedure FormPaint(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public { Public declarations } end;var Tringle: TTringle; n,xa, ya, xb, yb, xc, yc,q : Integer; w:string; a: array[0..10]of TColor; //задаем массив цветов.implementation

{$R *.dfm}

procedure TTringle.Triangle(xa, ya, xb, yb, xc, yc, n: Integer);

15

Page 16: Фракталы

var xp, xq, xr, yp, yq, yr: Integer;beginif n>0 thenbegin //вычисление координат середин сторон треугольникаxp:=(xb+xc) div 2;yp:=(yb+yc) div 2;xq:=(xa+xc) div 2;yq:=(ya+yc) div 2;xr:=(xb+xa) div 2;yr:=(yb+ya) div 2;a[0]:=clMaroon; //определяем значение каждого элемента массиваa[1]:=clPurple;a[2]:=clFuchsia;a[3]:=clAqua;a[4]:=clBlue;a[5]:=clBlue;a[6]:=clMaroon;a[7]:=clPurple;a[8]:=clFuchsia;a[9]:=clAqua;a[10]:=clBlue;for q:=0 to n do //задаем цикл для раскрашивания треугольникаTringle.Canvas.Pen.Color:=a[q];Tringle.Canvas.MoveTo(xp,yp); //Изображение средних линий треугольникаTringle.Canvas.LineTo(xq,yq);Tringle.Canvas.MoveTo(xq,yq);Tringle.Canvas.LineTo(xr,yr);Tringle.Canvas.MoveTo(xp,yp);Tringle.Canvas.LineTo(xr,yr);Triangle(xa, ya, xr, yr, xq, yq, n-1);Triangle(xb, yb, xp, yp, xr, yr, n-1);Triangle(xc, yc, xq, yq, xp, yp, n-1);end;end;procedure TTringle.FormPaint(Sender: TObject);beginTringle.Canvas.Pen.Color:=clPurple;xc:=300; yc:=0; xb:=600; yb:=400; xa:=0; ya:=400;// задание начальных значенийTringle.Canvas.MoveTo(xa,ya);Tringle.Canvas.LineTo(xb,yb);Tringle.Canvas.MoveTo(xb,yb);Tringle.Canvas.LineTo(xc,yc);Tringle.Canvas.MoveTo(xa,ya);Tringle.Canvas.LineTo(xc,yc);Triangle(xa,ya,xb,yb,xc,yc,StrToInt(w));end;

16

Page 17: Фракталы

Фрактальные изображения выглядят особенно красиво, если их раскрасить.

Это предусмотрено в программе для построения треугольника Серпинского.

Составляющие основной треугольники меняют цвета в зависимости от их

размера. Треугольники одинакового размера имеют одинаковый цвет. Самый

большой треугольник всегда окрашен в фиолетовый цвет.

Это организовано следующим

образом. В разделе описания глобальных переменных var мы задаем массив

из набора цветов (a: array[0..10]of TColor).

Затем определяем значение каждого элемента массива, то есть каждому из

элемента массива присваиваем определенный цвет. Для того, чтобы при

каждом последующем повторении программа использовала другой цвет

организуем цикл с параметром for. Этот цикл имеет следующую структуру:

For <параметр_цикла>:=<начальное_значение> to <конечное_значение>

Do <оператор>;

Начальное значение цикла будет равно 1 и цикл должен выполняться до тех

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

a[0]:=clMaroon; a[1]:=clPurple; a[2]:=clFuchsia; a[3]:=clAqua; a[4]:=clBlue; a[5]:=clBlue;a[6]:=clMaroon; a[7]:=clPurple; a[8]:=clFuchsia; a[9]:=clAqua; a[10]:=clBlue;//каждому элементу массива присваиваем определенный цветfor q:=0 to n do //задаем цикл для раскрашивания треугольникаTringle.Canvas.Pen.Color:=a[q];//рисование треугольников текущим цветомTringle.Canvas.MoveTo(xp,yp); Tringle.Canvas.MoveTo(xq,yq);Tringle.Canvas.LineTo(xr,yr);Tringle.Canvas.MoveTo(xp,yp);Tringle.Canvas.LineTo(xr,yr);Triangle(xa, ya, xr, yr, xq, yq, n-1);Triangle(xb, yb, xp, yp, xr, yr, n-1);

17

Page 18: Фракталы

Triangle(xc, yc, xq, yq, xp, yp, n-1); end;

Построение треугольника Серпинского в среде Visual Basic практически не

отличается от его построения в Delphi. Ниже приведен листинг программы.

Public xa As Integer, ya As Integer, xb As Integer, yb As Integer, xc As Integer, yc As Integer, n As Integer // объявление глобальных переменныхPrivate Sub triangle(xa As Integer, ya As Integer, xb As Integer, yb As Integer, xc As Integer, yc As Integer, n As Integer) //описываем процедуруDim xp As Integer, xq As Integer, xr As Integer, yp As Integer, yq As Integer, yr As Integer// объявление локальных переменныхIf n > 0 Thenxp = Int((xb + xc) / 2) //Нахождение координат средних линий треугольникаyp = Int((yb + yc) / 2)xq = Int((xa + xc) / 2)yq = Int((ya + yc) / 2)xr = Int((xb + xa) / 2)yr = Int((yb + ya) / 2)Line (xp, yp)-(xq, yq), RGB(90, 10, 500)Line (xq, yq)-(xr, yr), RGB(190, 10, 100)Line (xp, yp)-(xr, yr), RGB(190, 190, 300)Call triangle(xc, yc, xq, yq, xp, yp, n - 1)Call triangle(xa, ya, xr, yr, xq, yq, n - 1)Call triangle(xb, yb, xp, yp, xr, yr, n - 1)End If End SubPrivate Sub Command1_Click()treug.Scale (-50, -50)-(800, 600) // Задаем маштабtreug.Cls //предварительно очищаем форму от предыдущего рисункаn = Val(Text1.Text)Line (xa, ya)-(xb, yb), RGB(90, 190, 300)Line (xb, yb)-(xc, yc), RGB(90, 190, 300)Line (xa, ya)-(xc, yc), RGB(90, 190, 300)Call triangle(xa, ya, xb, yb, xc, yc, n)End SubPrivate Sub Form_Load()n = Val(Text1.Text)xc = 300yc = 0xb = 600yb = 400xa = 0 ya = 400End Sub

При построении фрактальной кривой используется графический метод Line.

Метод Line позволяет:

1) чертить на объекте, к которому этот метод применяется, отрезки прямых

линий;

18

Page 19: Фракталы

2) изображать на этом объекте закрашенные или не закрашенные

прямоугольники.

Метод Line имеет следующий синтаксис:

Вслед за ключевым словом Line через запятую следуют так называемые

параметры метода.

Имя Объекта может отсутствовать. В этом случае по умолчанию метод

применяется к экранной форме.

Параметр (XI, Y1) — (Х2, Y2) — это координаты границ отрезка или двух

углов прямоугольника — левого верхнего и правого нижнего (или наоборот

— правого нижнего и левого верхнего).

Параметр Цвет — это выражение, значением которого является число типа

Long, которым в Visual Basic кодируется тот или иной цвет.

Параметр Цвет может отсутствовать. Тогда по умолчанию он будет

совпадать со значением свойства ForeColor объекта.

В Visual Basic встроена функция RGB, которая рассчитывает код оттенков

красного, зеленого, синего цветов. Данная функция имеет следующий

синтаксис:

RGB(Red (код красного цв.), Green (код зеленого цв.), Blue (код синего цв.)

Наличие данной функции позволяет, например, проследить зависимость

цвета от координат. Рассмотрим это позже на примере аттракторов «Радуга»

и «Космос».

Параметр Флаг — это либо символ В, либо символы BF. В первом случае

рисуется не отрезок, а прямоугольник, во втором — закрашенный

прямоугольник. (Цвет закраски — это значение параметра Цвет.)

Отметим и то, что толщину отрезка или контура прямоугольника можно

увеличить. Для этого, следует увеличить значение свойства DrawWidth (по

умолчанию оно равно 2).

19

[ИмяОбъекта.] Line (Х1, Y1) — (Х2, Y2) [, Цвет [, Флаг ]]

Page 20: Фракталы

Рекурсивное построение кривой «Квадраты».

Построение данной кривой аналогично построению треугольника

Серпинского. Для квадрата находят середины его сторон. Эти точки

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

вписанный в первоначальный. К последующим квадратам применяется та

же процедура.

Листинг программы

построения кривой «Квадраты»

type TRect = class(TForm) procedure Rectangle(xa,ya,xb,yb,xc,yc,xd,yd,n:Integer); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end;var Rect: TRect; xa,ya,xb,yb,xc,yc,xd,yd,n,i,w: integer;

implementation

{$R *.dfm}

procedure TRect.Rectangle(xa,ya,xb,yb,xc,yc,xd,yd,n:integer);

20

Page 21: Фракталы

var xp,yp,xr,yr,xq,yq,xf,yf: integer;beginif n>0 then beginRect.Canvas.Pen.Color:=clBlack;xp:=(xa+xb) div 2; //нахождение середин сторонyp:=(ya+yb) div 2;xr:=(xb+xc) div 2;yr:=(yb+yc) div 2;xq:=(xc+xd) div 2;yq:=(yc+yd) div 2;xf:=(xa+xd) div 2;yf:=(ya+yd) div 2;Rect.Canvas.MoveTo(xp,yp);Rect.Canvas.LineTo(xr,yr);Rect.Canvas.MoveTo(xr,yr);Rect.Canvas.LineTo(xq,yq);Rect.Canvas.MoveTo(xq,yq);Rect.Canvas.LineTo(xf,yf);Rect.Canvas.MoveTo(xf,yf);Rect.Canvas.LineTo(xp,yp);Rectangle(xp,yp,xr,yr,xq,yq,xf,yf,n-1);end;end;procedure TRect.FormPaint(Sender: TObject);beginRect.Canvas.Pen.Width:=2; xa:=0; ya:=500; //задание начальных значенийxb:=500; yb:=500;xc:=500; yc:=50;xd:=0; yd:=50;Rectangle(xa,ya,xb,yb,xc,yc,xd,yd,n);end;

Примечание. Используемые методы класса Canvas.

Метод Описание

FillRect(const Rect: TRect);*

Заполняет текущей кистью прямоугольную область Rect, включая ее левую и верхнюю границу, но не затрагивая правую и нижнюю границы.

MoveTo(x,y: Integer); Перемещает перо в положение (x,y) без вычерчивания линий.

TextOut(x,y: integer; const Text: String);

Выводит текстовую строку Text так, чтобы левый верхний угол прямоугольника, охватывающего текст, располагался в точке (х,у).

21

Page 22: Фракталы

*Метод FillRect удобно использовать для удаления изображения. Нужно

просто задать цвет заливки таким же, как цвет формы и в скобках указать

всю область формы: Form1.Canvas.FillRect(Form1.ClientRect) ;

22

Page 23: Фракталы

Листинг программы для построения кривой «Квадраты» в Visual Basic

Public xa As Integer, ya As Integer, xb As Integer, yb As Integer, xc As Integer, yc As Integer, n As Integer, xd As Integer, yd As Integer

Private Sub triangle(xa As Integer, ya As Integer, xb As Integer, yb As Integer, xc As Integer, yc As Integer, xd As Integer, yd As Integer, n As Integer)Dim xp As Integer, yp As Integer, xr As Integer, yr As Integer, xq As Integer, yq As Integer, xf As Integer, yf As IntegerIf n > 0 Thenxp = Int((xa + xb) / 2)yp = Int((ya + yb) / 2)xr = Int((xb + xc) / 2)yr = Int((yb + yc) / 2)xq = Int((xc + xd) / 2)yq = Int((yc + yd) / 2)xf = Int((xa + xd) / 2)yf = Int((ya + yd) / 2)Line (xp, yp)-(xr, yr), RGB(90, 10, 500)Line (xr, yr)-(xq, yq), RGB(10, 30, 200)Line (xq, yq)-(xf, yf), RGB(190, 0, 300)Line (xf, yf)-(xp, yp), RGB(0, 0, 500)Call triangle(xp, yp, xr, yr, xq, yq, xf, yf, n - 1)End IfEnd Sub

Private Sub Command1_Click()kvad.Scale (-10, -10)-(600, 600)kvad.Clsn = Val(Text1.Text)Call triangle(xa, ya, xb, yb, xc, yc, xd, yd, n)End Sub

Private Sub Form_Load()n = Val(Text1.Text)xc = 500yc = 50xb = 500yb = 500xa = 0ya = 500xd = 0yd = 50End Sub

23

Page 24: Фракталы

Вы, наверное, часто видели довольно хитроумные картины, на которых

непонятно что изображено, но все равно необычность их форм завораживает

и приковывает внимание. Как правило, кажется, что эти хитроумные формы

не поддаются какому-либо математическому описанию. Однако такие

картины могут быть порождены многократным применением формулы,

связывающей каким-либо образом координаты x и у. Эти картины

называются аттракторами. Рассмотрим формулу, придуманную Мартином из

Астонского университета:

Здесь новые значения Х и У оригинально связаны со старыми: новый Х

зависит от старого У, а новый У от старого Х, причем чтобы процесс не

пошел «вразнос», при вычислении Х от старого У отнимается Х1/2 . А для

того, чтобы ситуация нами контролировалась введены коэффициенты a,b и с.

Посмотрим, как уложатся точки, если их координаты менять по

приведенной формуле, ─ результат будет необычайно красив.

Листинг программы реализации аттрактора «Звездное небо»

procedure Tpoint.Paint;var q,i,x,x1,y,a,b,c: integer;beginif n>0 then begins[0]:=clBlue; //каждому элементу массива задаем определенный цветs[1]:=clred;s[2]:=clyellow;s[3]:=clAqua;s[4]:=clPurple;s[5]:=clGreen;s[6]:=clFuchsia;s[7]:=clWhite;repeatPoint.Canvas.MoveTo(x,y);a:=StrToInt(Edit1.Text); //значения коэффициентов будут вводиться пользователем в текстовые поляb:=StrToInt(Edit2.Text);

24

Page 25: Фракталы

c:=StrToInt(Edit3.Text);for i:=1 to 1000 dobeginfor q:=0 to 7 dobeginPoint.Font.Color:=s[q];p:=10; //искусственно вводим переменную для остановки циклаx1:=x;x:=trunc(y-sqrt(abs(b*x1-c)))-100;y:=a-x1;Point.Canvas.TextOut(x+300,y+100,'*');end; end;end;untilp=10;end;end;procedure Tpoint.FormPaint(Sender: TObject);var q:integer;beginpaint; //рисуем «звездное небо»end;

Запустив программу и введя наугад три числа 33, 33 и 33, получим узор,

напоминающий цветок.

25

Page 26: Фракталы

Числа 1, 1, 1000 дадут спираль.

Можно вводить любые числа и наблюдать за изменением узора. Особенно

интересные картины получаются, когда меняется одно из трех чисел, а

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

«звездное небо» или выродился в несколько точек.

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

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

случайного выбора randomize. Например, можно создать кнопку, после

нажатия на которую в текстовые поля будут занесены случайные числа.

Обработчик события OnClick должен выглядеть следующим образом:

procedure Tpoint.Button2Click(Sender: TObject);beginrandomize;Edit1.Text:=IntToStr(random(1000)+11);Edit2.Text:=IntToStr(random(1000)+11);Edit3.Text:=IntToStr(random(1000)+11);end;

26