Sunteți pe pagina 1din 16

Cursul 4

Fractali pe bază de motive iterate

Primii fractali studiaţi, mulţimea lui Cantor, pătratul lui Sierpinski, curba lui von Koch, ş.a., au fost construiţi prin repetarea la infinit a unei anumite reguli de generare, prin care o figu- ră iniţială, numită bază, este înlocuită cu o alta, numită motiv, în care se regăseşte de mai multe ori figura de bază, eventual redusă la scară, rotită, simetrizată sau translatată. De exemplu, construcţia pătratului lui Sierpinski se încadrează în această schemă: în fiecare etapă înlocuim fiecare pătrat bază cu câte un motiv format din 8 pătrăţele cu latura micşorată de trei ori. In etapa următoare, fiecare din cele 8 pătrăţele devine bază pentru aplicarea motivului. Analog, construcţia curbei lui von Koch se obţine prin înlocuirea repetată a fiecărui segment vechi cu patru segmente noi, dispuse după un anumit model.

vechi cu patru segmente noi, dispuse după un anumit model. Acest procedeu de construcţie este foarte

Acest procedeu de construcţie este foarte asemănător cu creşterea organismelor vii, unde, de exemplu, fiecare celulă (baza) se divide şi formează alte două celule (motivul). Spre deosebire de fractali, aici numărul de generaţii este finit iar regula de generare se poate schimba pe parcurs.

finit iar regula de generare se poate schimba pe parcurs. Un alt exemplu îl dau plantele

Un alt exemplu îl dau plantele arborescente a căror creştere anuală poate fi modelată cu următoarea regulă de generare: pe fiecare ramură verde apare un nod din care pleacă una sau mai

1

multe ramuri noi. Partea dintre nodul vechi şi nodul nou se lemnifică şi nu mai participă la gene- rare.

In continuare prezentăm câteva clase C# care desenază astfel de fractali. In toate exem- plele date aici baza este un segment iar motivul este format din două sau mai multe segmente. In fiecare etapă figura este formată din succesiunea segmentelor de bază, ale căror capete sunt memorate într-o listă de tip ComList. Toate clasele utilizate sunt dotate cu metoda transforma(ref ComList li) care par- curge lista primită, reconstinue succesiunea segmentelor de bază ale figurii, aplică pe fiecare bază motivul şi construieşte o nouă listă cu capetele noilor segmente. In final, lista nouă este returnată prin referinţă, deci în locul celei vechi.

1. Curba lui von Koch

deci în locul celei vechi. 1. Curba lui von Koch public class VonKoch : FractalForm {

public class VonKoch : FractalForm

{

static double theta = Math.PI / 6; static double ro = 0.5 / Math.Cos(theta); static Complex w = Complex.setRoTheta(ro, theta); static double lambda = 1 / 3.0;

void transforma(ref ComList li) //VonKoch

{

ComList rez = new ComList(); Complex z1, z2, delta; //Segmentul z1_z2 este inlocuit cu //z1_zA, zA_zB, zB_zC si zC_z2, unde //zA=z1 + lambda* (z2 - z1)

2

//zB=z1 + w * (z2 - z1)) //zC=z1 + (1-lambda) * (z2 - z1).

rez.nextZet = z1 = li.firstZet;

for (z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

delta = z2 - z1; rez.nextZet = z1 + lambda * delta; rez.nextZet = z1 + w * delta; rez.nextZet = z2 - lambda * delta; rez.nextZet = z2; z1 = z2;

}

li = rez;

}

void whiteScreen()

{

initScreen(); for (int i = imin; i <= imax; i++) for (int j = jmin; j <= jmax; j++) setPixel(i, j, Color.White);

}

void traseaza(ComList li)

{

Complex z1 = li.firstZet; whiteScreen();

for (Complex z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

setLine(z1, z2, Color.Black); z1 = z2;

}

delaySec(0.5);

}

public override void makeImage()

{

setXminXmaxYminYmax(-1.1, 1.1, -0.5, 1.5); ComList fig = new ComList(); //segmentul initial fig.nextZet = -1; fig.nextZet = +1; traseaza(fig); for (int k = 0; k <= 5; k++)

{

transforma(ref fig); traseaza(fig); if (!resetScreen()) return;

}

}

}

3

Rezultat:

Rezultat: 4

4

2. Curba lui von Koch în pătrat

public class VonKoch4 : FractalForm

{

static Complex i = new Complex(0, 1); static double theta = Math.PI / 4.1; static double ro = 0.5 / Math.Cos(theta);

static Complex w = Complex.setRoTheta(ro, theta); static double lambda = 1 / 2.1; void transforma(ref ComList li) //VonKoch

{

ComList rez = new ComList(); Complex z1, z2, delta; //Segmentul z1_z2 este inlocuit cu //z1_zA, zA_zB, zB_zC si zC_z2, unde //zA=z1 + lambda* (z2 - z1) //zB=z1 + w * (z2 - z1)) //zC=z1 + (1-lambda) * (z2 - z1). rez.nextZet = z1 = li.firstZet;

for (z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

delta = z2 - z1; rez.nextZet = z1 + lambda * delta; rez.nextZet = z1 + w * delta; rez.nextZet = z2 - lambda * delta; rez.nextZet = z2; z1 = z2;

}

li = rez;

}

void whiteScreen()

{

initScreen(); for (int i = imin; i <= imax; i++) for (int j = jmin; j <= jmax; j++) setPixel(i, j, Color.White);

}

void traseaza(ComList li)

{

Complex z1 = li.firstZet; whiteScreen(); int n = 1;

for (Complex z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

setLine(z1, z2, getColor(++n / 500)); z1 = z2;

}

}

public override void makeImage()

{

setXminXmaxYminYmax(-0.1, 1.1, -0.1, 1.1); ComList fig = new ComList(); //patratul initial fig.nextZet = 0; fig.nextZet = 1; fig.nextZet = 1 + i; fig.nextZet = i;

5

fig.nextZet = 0;

for (int k = 0; k <= 8; k++)

{

transforma(ref fig); traseaza(fig); if (!resetScreen()) return;

}

}

}

Rezultat pentru lambda = 1 / 2.1 şi theta = Math.PI / 4.1:

traseaza(fig); if (!resetScreen()) return ; } } } Rezultat pentru lambda = 1 / 2.1 şi

6

Rezultat pentru lambda = 1 / 2.0 şi theta = Math.PI / 4.0:

Rezultat pentru lambda = 1 / 2.0 şi theta = Math .PI / 4.0: 7

7

3. Crabul

3. Crabul public class Crab : FractalForm { static Complex i = new Complex (0, 1);

public class Crab : FractalForm

{

static Complex i = new Complex(0, 1); static double theta = Math.PI / 4.0; static double ro = 0.5 / Math.Cos(theta); static Complex w = Complex.setRoTheta(ro, theta);

void transforma(ref ComList li) //Crab

{

ComList rez = new ComList(); Complex z1, z2; //Segmentul z1_z2 este inlocuit cu z1_zA si zA_z2 //unde zA=z1+w*(z2-z1). rez.nextZet = z1 = li.firstZet; for (z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

rez.nextZet = z1 + w * (z2 - z1); rez.nextZet = z2; z1 = z2;

}

li = rez;

}

void whiteScreen()

{

initScreen(); for (int i = imin; i <= imax; i++) for (int j = jmin; j <= jmax; j++) setPixel(i, j, Color.White);

}

8

void traseaza(ComList li)

{

Complex z1 = li.firstZet; int n = 1; whiteScreen(); setAxis(); for (Complex z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

setLine(z1, z2, getColor(++n / 30)); z1 = z2;

}

delaySec(0.5);

}

public override void makeImage()

{

setXminXmaxYminYmax(-1, 2, -1.5, 1.5); ComList fig = new ComList(); //segmentul initial fig.nextZet = 0; fig.nextZet = 1; for (int k = 0; k < 19; k++)

{

transforma(ref fig); traseaza(fig); if (!resetScreen()) return;

}

}

}

Rezultat:

( int k = 0; k < 19; k++) { transforma( ref fig); traseaza(fig); if (!resetScreen())

9

4. Dragonul

4. Dragonul public class Dragon : FractalForm { static Complex i = new Complex (0, 1);

public class Dragon : FractalForm

{

static Complex i = new Complex(0, 1); static double theta = Math.PI / 4.0; static double ro = 0.5 / Math.Cos(theta); static Complex w1 = Complex.setRoTheta(ro, theta); static Complex w2 = Complex.setRoTheta(ro, -theta);

void transforma(ref ComList li) //Dragon

{

ComList rez = new ComList(); Complex z1, z2, w; //Segmentul z1_z2 este inlocuit cu z1_zA si zA_z2 //unde zA=z1+w*(z2-z1) cu w avand in mod //alternativ valoarea w1 sau w2. int sign = 1; rez.nextZet = z1 = li.firstZet; for (z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

sign *= -1; w = (sign > 0 ? w2 : w1); rez.nextZet = z1 + w * (z2 - z1); rez.nextZet = z2; z1 = z2;

}

li = rez;

}

void whiteScreen()

{

initScreen(); for (int i = imin; i <= imax; i++) for (int j = jmin; j <= jmax; j++) setPixel(i, j, Color.White);

}

10

void traseaza(ComList li)

{

Complex z1 = li.firstZet; int n = 1; whiteScreen(); setAxis(); for (Complex z2 = li.nextZet; !li.ended; z2 = li.nextZet)

{

setLine(z1, z2, getColor(++n / 30)); z1 = z2;

}

delaySec(0.5);

}

public override void makeImage()

{

setXminXmaxYminYmax(-0.5, 1.5, -1, 1); ComList fig = new ComList(); //segmentul initial fig.nextZet = 0; fig.nextZet = 1; for (int k = 0; k < 19; k++)

{

transforma(ref fig); traseaza(fig); if (!resetScreen()) return;

}

}

}

= 1; for ( int k = 0; k < 19; k++) { transforma( ref fig);

11

5. Arbori

public class Copac : FractalForm

{

static Complex i = new Complex(0, 1); static double roTrunchi = 0.9; static double roRam = 0.6; static double thetaRam = Math.PI / 7; static Complex omega_stg = Complex.setRoTheta(roRam, thetaRam); static Complex omega_drp = Complex.setRoTheta(roRam, -thetaRam);

void transforma(ref ComList li) //Copac

{

ComList rez = new ComList(); Complex z0, z1, zV, zA, zB, delta;

for (z0 = li.firstZet; !li.ended; z0 = li.nextZet)

{

z1 = li.nextZet; zV = z1 + roTrunchi * (z1 - z0); delta = zV - z1; zA = z1 + omega_stg * delta; zB = z1 + omega_drp * delta; rez.nextZet = z1; rez.nextZet = zA; rez.nextZet = z1; rez.nextZet = zV; rez.nextZet = z1; rez.nextZet = zB;

}

li = rez;

}

void whiteScreen()

{

initScreen(); for (int i = imin; i <= imax; i++) for (int j = jmin; j <= jmax; j++) setPixel(i, j, Color.White);

}

void traseaza(ComList li)

{

 

Complex z; for (z = li.firstZet; !li.ended; z = li.nextZet) setLine(z, li.nextZet, Color.Black);

delaySec(0.2);

}

public override void makeImage()

{

setXminXmaxYminYmax(-1.1, 1.1, 0 - 0.1, 2.1); ComList fig = new ComList(); Complex z0 = 0, z1 = 0.37 * i; fig.nextZet = z0; fig.nextZet = z1; whiteScreen(); traseaza(fig);

12

for (int k = 1; k <= 6; k++)

{

transforma(ref fig); traseaza(fig); if (!resetScreen()) return;

}

}

}

for ( int k = 1; k <= 6; k++) { transforma( ref fig); traseaza(fig); if

13

6. Păduri

Pentru ca arborii desenaţi de noi să aibe un aspect cât de cât natural trebuie să adaugăm mai multă culoare şi, mai ales, să folosim numere aleatoare pentru a adăuga un “zgomot de fond” în procesul de generare. Iată un rezultat obţinut detul de uşor:

aleatoare pentru a adăuga un “zgomot de fond” în procesul de generare. Iată un rezultat obţinut

14

public class Padure : FractalForm

{

void unPom(Complex zz0, Complex deltaz0, int nrEtape, Color colTr, Color colFl)

{

Complex z0, z1, zV, zA, zB, delta, i = new Complex(0, 1); Color col = colTr; double roTrunchi1, roTrunchi = 0.8; double roRam1, roRam = 0.7; double thetaRam1, thetaRam = Math.PI / 15; double thetaTrunchi; Complex omega_stg, omega_drp, omega_tr;

ComList oldList = new ComList(); ComList newList = new ComList(); z0 = zz0; z1 = zz0 + deltaz0; oldList.nextZet = z0; oldList.nextZet = z1; setLine(z0, z1, col); Random nRand = new Random();

for (int k = 1; k <= nrEtape; k++)

{

for (z0 = oldList.firstZet; !oldList.ended; z0 = oldList.nextZet)

{

z1 = oldList.nextZet; roTrunchi1 = roTrunchi + nRand.NextDouble() / 10; thetaTrunchi = (nRand.NextDouble() - 0.5) / 5;

omega_tr = Complex.setRoTheta(roTrunchi1, thetaTrunchi); zV = z1 + omega_tr * (z1 - z0); delta = zV - z1; roRam1 = roRam + nRand.NextDouble() / 5; thetaRam1 = thetaRam + nRand.NextDouble() / 2; omega_stg = Complex.setRoTheta(roRam1, thetaRam1); roRam1 = roRam + nRand.NextDouble() / 10; thetaRam1 = thetaRam + nRand.NextDouble() / 2; omega_drp = Complex.setRoTheta(roRam1, -thetaRam1); zA = z1 + omega_stg * delta; zB = z1 + omega_drp * delta; //if (k == kmax) col = Color.Green; if (nRand.NextDouble() < 0.9)

{

newList.nextZet = z1; newList.nextZet = zA; setLine(z1, zA, col);

}

if (nRand.NextDouble() < 0.95)

{

newList.nextZet = z1; newList.nextZet = zV;

15

setLine(z1, zV, col);

}

if (nRand.NextDouble() < 0.9)

{

newList.nextZet = z1; newList.nextZet = zB; setLine(z1, zB, col);

}

}

roTrunchi *= 0.92; oldList = newList; newList = new ComList(); if (!resetScreen()) return;

//delaySec(0.2);

}

for (z1 = oldList.firstZet; !oldList.ended; z1 = oldList.nextZet)

{

 

col = colFl;

z1 = oldList.nextZet; int ix = getI(z1.Re); int jy = getJ(z1.Im); setPixel(Complex.setReIm(getX(ix), getY(jy)), col); setPixel(Complex.setReIm(getX(ix + 1), getY(jy)), col); setPixel(Complex.setReIm(getX(ix - 1), getY(jy)), col); setPixel(Complex.setReIm(getX(ix), getY(jy + 1)), col); setPixel(Complex.setReIm(getX(ix), getY(jy - 1)), col); //if (!resetScreen()) return;

}

if (!resetScreen()) return;

}

public override void makeImage()

{

setXminXmaxYminYmax(0, 1, 0, 1); //setAxis(); Random nRand = new Random(); Complex z0, delta; Color colTr, colFr;

for (int n = 0; n < 100; n++)

{

z0 = Complex.setReIm(nRand.NextDouble(), nRand.NextDouble() / 2); delta = Complex.setReIm((nRand.NextDouble() - 0.5) / 100, 0.05 + nRand.NextDouble() / 5); colTr = getColor(500 + nRand.Next(100)); colFr = getColor(600 + nRand.Next(100)); if (nRand.Next(100) < 20) colFr = getColor(200 +

unPom(z0, delta, 8, colTr, colFr);

}

}

}

16

nRand.Next(100));