Sunteți pe pagina 1din 22

Clase C# pentru grafic 2D

Proiectul FractalExplorer descris mai jos a fost conceput ca punct de plecare, ca un ablon iniial, n dezvoltarea de aplicaii C# de grafic bidimensional cu ajutorul mediului de dezvoltare Microsoft Visual C# 2008. La rulare, programul afieaz o form cu dimensiuni fixe pe care se afl o suprafa de desenare, colorat iniial n negru (un obiect PictureBox), i un meniu cu cinci intrri (Start, Stop, Save, About i Exit). Un clic pe <Start> declaneaz trasarea desenului, <Stop> o oprete, <Save> permite salvarea imaginii obinute n format bitmap iar <Exit> nchide programul. Submeniul <About> afieaz csua de dialog corespunztoare.

Iat declaraiile clasei formei principale (extrase din fiierul FractalForm.Designer.cs), declaraii scrise n mod automat de mediul de dezvoltare n etapa de proiectare:
public partial class FractalForm : Form {... protected System.Windows.Forms.PictureBox picBox; private System.Windows.Forms.MenuStrip mainMenu; private System.Windows.Forms.ToolStripMenuItem menuToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem startToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem stopToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; private System.Windows.Forms.SaveFileDialog mySaveFileDialog; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; ... }

Declaraiile scrise de programator n cod sunt urmtoarele (n fiierul FractalForm.cs):


public partial class FractalForm : Form {... protected Bitmap bmp; protected Color[] paleta; protected Color penColor; protected const int dimPaleta=1024; protected const int dimPicBox=602; protected const int dimPicBmp = 600; protected int imax, imin, jmax, jmin; protected double xmax, xmin, ymax, ymin; protected double dxdi, dydj, didx, djdy; protected bool doWork; ... }

Bitmap-ul bmp este folosit pentru pstrarea, n memoria RAM, a pixelilor desenai n program; pentru a deveni vizibil el trebuie atribuit proprietii Image a picture-box-ului prin instruciunea
picBox.Image = bmp;

Aceast setare apare n dou locuri: n metoda protected void initScreen() apelat la clic pe <Start> i n tratarea evenimentului VisibleChanged cnd forma trebuie re-pictat pe ecran. Pixelii sunt setai cu ajutorul metodei Bitmap.SetPixel(int i, int j, Color c) iar bitmapul este iniializat cu instruciunea:
bmp = new Bitmap(dimPicBmp, dimPicBmp, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

In orice program de grafic 2D avem dou sisteme de referin: cel al punctelor din plan, de coordonate (x,y) , x i y numere reale i cel al pixelilor de pe ecran, de coordonate (i, j), i i j numere ntregi. Pe ecran apar numai pixelii din dreptunghiul delimitat de imin, imax, jmin,
2

care conine imaginea din plan aflat n dreptunghiul delimitat de xmin, xmax, ymin, ymax. Transformrile afine care suprapun cele dou dreptunghiuri folosesc factorii de scalare dxdi, dydj, didx, djdy, calculai astfel:
jmax, dxdi dydj didx djdy = = = = (xmax (ymax (imax (jmax xmin) ymin) imin) jmin) / / / / (imax (jmax (xmax (ymax imin); jmin); xmin); ymin);

Dreptunghiul pixelilor este fixat din start, n constructor:


imin = 0; imax = dimPicBmp-1; jmin = 0; jmax = dimPicBmp-1;

n timp ce dreptunghiul din planul xy poate fi setat de programator cu funcia membru


void setXminXmaxYminYmax(double xm, double XM, double ym, double YM);

Trecerea de la coordonatele (x, y) la (i, j) se face cu formulele:


i = (int)(imin + (x - xmin) * didx); j = (int)(jmin + (y - ymin) * djdy);

iar trecerea invers cu formulele:


x = (double)(xmin+(i-imin)*dxdi); y = (double)(ymin+(j-jmin)*dydj);

Culorile folosite pot fi iniializate prin instruciuni de forma:


Color c1, c2, c3; c1 = Color.Azure; c2 = Color.FromArgb(128, 255, 17); c3 = penColor;

deoarece penColor este un obiect Color iniializat la ncrcarea formei:


penColor = Color.White;

sau prin utilizarea paletei de culori

protected Color[] paleta; paleta = new Color[dimPaleta]; for (int k = 0; k < dimPaleta; k++) { double tcol = 56.123 + 2.0 * Math.PI * k / (double)dimPaleta; int rcol = (int)(128 + 128 * Math.Sin(tcol)); int gcol = (int)(128 + 128 * Math.Sin(2 * tcol)); int bcol = (int)(128 + 128 * Math.Cos(3 * tcol)); paleta[k] = Color.FromArgb(rcol % 256, gcol % 256, bcol % 256); }

care este setat odata cu penColor prin secvena:

Accesul la culorile din palet poate fi direct sau prin intermediul metodei Exemplu:
Color c1, c2; c1 = paleta[453]; c2 = getColor(453); //in clasa si in descendenti //in afara

public Color getColor(int k) { return paleta[k % dimPaleta]; }

In sfrit, ultima variabil membru a clasei FractalForm declarat aici,


protected bool doWork;

are rolul de a indica dac programul trebuie sau nu s stopeze desenarea. La selectarea itemului <Start> se seteaz doWork cu valoarea true i este lansat n execuie funcia de desenare
3

makeImage(). Apsarea lui <Stop> sau <Exit> seteaz doWork cu false. Desenarea poate fi o operaie de lung durat care s ina procesorul ocupat n totalitate un timp nepermis de lung i din acest motiv trebuie consultat, din cnd n cnd, valorea variabilei doWork, prin apelarea funciei
protected bool resetScreen() { picBox.Invalidate(); Application.DoEvents(); return doWork; }

Observm c resetScreen()are un rol triplu: 1. actualizarea imaginii: invalideaz imaginea obiectului picBox i provoac astfel repictarea sa (i astfel pixelii colorai de noi n bitmap-ul din memorie apar pe ecran), 2. ascultarea evenimentelor: oblig sistemul de operare s trateze eventualele evenimente aprute i s modifice valoarea lui doWork dac este cazul (altfel programul ar bloca activitatea calculatorului) 3. acionare: informeaz funcia apelant, prin intermediul valorii lui doWork, dac s-a apsat <Stop> sau <Exit> (caz n care trebuie oprit desenarea). Modul standard de lucru este urmtorul:
public override void makeImage() //in clasa Sablon { setXminXmaxYminYmax(-1.0, 1.0, -1.0, 1.0); ... for (int k = 0; k<1000000; k++) //desenam o serie de figuri { col = getColor(k); for ( ...) //formam o figura intreaga { ... setPixel(x,y, col); //coloram un singur punct ... } if (!resetScreen()) return; //actualizam, ascultm, actionam } }

Metodele grafice puse la dispoziia programatorului au un caracter minimal (clasa Bitmap dispune numai de funcia SetPixel, spre deosebire de clasa Graphics, special conceput pentru grafica 2D, dar care ar fi impus o abordare mai laborioas). Mai precis, au fost implementate numai funciile:
protected protected protected protected protected protected void void void void void void setPixel(int i, int j, Color c); setPixel(double x, double y, Color c); setPixel(Complex z, Color c); setLine(int i0, int j0, int i1, int j1, Color c); setLine(double x0, double y0, double x1, double y1, Color c); setLine(Complex z0, Complex z1, Color c);

In sfrsit, pentru trasarea rapid a axelor de coordonate se poate apela funcia


4

protected void setAxis() { setLine(xmin, 0.0, xmax, 0.0, penColor); setLine(0.0, ymin, 0.0, ymax, penColor); }

Clasa FractalForm are rolul de a fi clas de baz pentru aplicaii de grafic 2D. Pentru a facilita dezvoltarea acestora, clasa FractalForm a fost prevzut cu dou metode virtuale
public virtual void makeTitle(){...}

i
public virtual void makeImage() {...}

care pot fi deci suprascrise n clasele motenitoare. De fapt, o clas derivat care execut un desen oarecare n plan se poate rezuma numai la suprascrierea acestor dou metode. Exemplu:
public class Sablon : FractalForm { public override void makeTitle() { this.Text = "SABLON"; } public override void makeImage() { setXminXmaxYminYmax(-10, 20, -10, 20); setAxis(); double ro, theta; Complex z0,a,i=new Complex(0,1); Color col; z0 = 5+5*i; a=Complex.setRoTheta(0.99, Math.PI/24); ListaCom oldList = new ListaCom(); ListaCom newList = new ListaCom(); for (theta = 0, ro=7; theta < 2 * Math.PI; theta += 0.01) { oldList.adaugaNod(Complex.setRoTheta(ro, theta)); } for (int k = 0; k<500; k++) { col = getColor(100 + 2*k); for (NodCom p = oldList.primulNod; p != null; p = p.next) { setPixel(p.z, col); newList.adaugaNod( z0+a*(p.z-z0)); } oldList=newList; newList = new ListaCom(); if (!resetScreen()) return; //delaySec(0.2); } } }

In acest exemplu figurile din plan sunt desenate cu ajutorul numerelor complexe, utiliznd structura Complex definit n fisierul Complex.cs. In acelai fiier mai sunt definite i clasele
5

i ListaCom, un obiect de tip ListaCom fiind o list simplu nlnuit de noduri NodCom, fiecare nod fiind format numai dintr-un numr complex i o referin la urmtorul nod:
NodCom public class NodCom //noduri pentru o lista de numere complexe { public Complex z; public NodCom next; public NodCom() { z = new Complex(); next = null; } public NodCom(NodCom p) //constructorul de copiere { this.z = p.z; this.next = p.next; } public NodCom(Complex z) { this.z = z; //nu este nevoie de copiere, //Complex este o structura this.next = null; } public NodCom(double xx, double yy) { this.z = new Complex(xx, yy); this.next = null; } } public class ListaCom // Lista simplu inlantuita cu noduri de tip NodCom { public NodCom primulNod; private NodCom ultimulNod; public ListaCom() { primulNod = null; ultimulNod = null; } public ListaCom(ListaCom li) //Constructorul de copiere { primulNod = null; ultimulNod = null; for (NodCom p = li.primulNod; p != null; p = p.next) { this.adaugaNod(p); } } public void adaugaNod(NodCom p) { NodCom pp = new NodCom(p); //copiem nodul primit if (primulNod == null) ultimulNod = primulNod = pp;//init. lista else ultimulNod = ultimulNod.next = pp; //continuare lista }

public void adaugaNod(Complex z) { NodCom p = new NodCom(z); if (primulNod == null) ultimulNod = primulNod = p;//init. lista else ultimulNod = ultimulNod.next = p; //continuare lista } }

S urmrim utilizarea acestor clase n funcia makeImage() din exemplul de mai sus. Dup ce, cu instruciunile
setXminXmaxYminYmax(-10, 20, -10, 20); setAxis();

este stabilit dreptunghiul din planul xOy care va fi reprezentat pe ecran i sunt trasate axele de coordonate, este ncrcat n lista oldList o figur iniial, adic o mulime (finit) de numere complexe. Mai precis, n ciclul for
for (theta = 0, ro=7; theta < 2 * Math.PI; theta += 0.01) { oldList.adaugaNod(Complex.setRoTheta(ro, theta)); }

sunt adugate n list numerele complexe de pe cercul de raz ro=7, centrat in origine, ncepnd cu numrul de argument theta = 0 i continund cu cele aflate prin parcurgerea cercului n sens trigonometric cu pasul de 0.01 radiani. Aceast figur iniial este transformat apoi, n mod repetat de 500 de ori, prin transformarea
T(z)=z0+a*(z-z0);

transformare format dintr-o rotaie n jurul lui z0 = 5+5*i de unghi arg(a)=pi/24,compus cu o omotetie de centru z0 i raport |a|=0.99. La fiecare pas este parcurs lista oldList, punctele gsite sunt colorate (toate cu aceeai culoare col) i puse n bitmap-ul bmp iar imaginile lor prin T sunt adugate listei newList.
for (int k = 0; k<500; k++) { col = getColor(100 + 2*k); for (NodCom p = oldList.primulNod; p != null; p = p.next) { setPixel(p.z, col); newList.adaugaNod( z0+a*(p.z-z0)); } oldList=newList; newList = new ListaCom(); if (!resetScreen()) return; }

Dup desenarea i transformarea ntregii figuri din lista veche, pregtim reluarea iterrii prin transferul listei noi n lista veche i re-iniializarea listei noi. Afiarea bitmap-ului pe ecran se obine prin apelarea metodei resetScreen(), apel necesar i din alte motive, vezi mai sus. In final se obine imaginea din instantaneul din prima pagin.

Anexe 1. Fiierul AboutForm.cs


using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows.Forms; System.Drawing;

namespace FractalExplorer { class AboutForm : Form { private string[] texte; private RichTextBox txtInfo; private Button btnOK;

public AboutForm() { texte = new string[]{ "Program C# pentru cursul de \"FRACTALI\"", " ", "Anul III matematica-informatica, 2008/2009", "Facultatea de Matematica", "Universitatea \"Al. I. Cuza\" din Iasi, Romania", " ", "\u00a9 2009 Prenume Nume",}; this.Text = "About"; this.StartPosition = FormStartPosition.WindowsDefaultLocation; this.FormBorderStyle = FormBorderStyle.FixedDialog; this.Height = 10 * this.Width / 16; this.ControlBox = false; txtInfo = new RichTextBox(); txtInfo.Left = 15; txtInfo.Top = 18; txtInfo.Width = this.Width - 40; txtInfo.Height = 6+this.Height / 2; txtInfo.Lines = texte; txtInfo.BackColor = Color.Black; txtInfo.ForeColor = Color.Silver; txtInfo.ReadOnly = true; txtInfo.Visible = true; this.Controls.Add(txtInfo); btnOK = new Button(); btnOK.Text = "OK"; btnOK.Left = this.ClientRectangle.Width - btnOK.Width - 20; btnOK.Top = this.ClientRectangle.Height - btnOK.Height - 8;

btnOK.Visible = true; btnOK.Click += new EventHandler(btnOK_Click); this.Controls.Add(btnOK); btnOK.Select();

} private void btnOK_Click(object sender, EventArgs eArgs) { this.Close(); } } }

2. Fiierul Complex.cs
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace FractalExplorer { public struct Complex { public double x; public double y; public Complex(double x, double y) { this.y = y; this.x = x; } public override string ToString() { double eps = 1.0e-12; if (Math.Abs(y) < eps) // z=real return string.Format("{0}", x); if (Math.Abs(x) < eps) // z=imaginar { if (Math.Abs(y - 1) < eps) //z=i return "i"; if (Math.Abs(y + 1) < eps) //z=-i return "-i"; return string.Format("{0}i", y); } if (y > 0) return string.Format("{0}+{1}i", x, y); return string.Format("{0}{1}i", x, y);

public void show() { Console.WriteLine(this);

} public double Ro { get { return Math.Sqrt(x * x + y * y); } } public double Ro2 { get { return x * x + y * y; } } public double Theta { get { return Math.Atan2(y, x); } } public double Re { get { return x; } set { x = value; } } public double Im { get { return y; } set { y = value; } } public Complex conj { get { return new Complex(x, -y); } } public static Complex setRoTheta(double Ro, double theta) { return new Complex(Ro * Math.Cos(theta), Ro * Math.Sin(theta)); }

10

public static Complex setReIm(double x, double y) { return new Complex(x, y); } public static Complex operator +(Complex zst, Complex zdr) { return new Complex(zst.x + zdr.x, zst.y + zdr.y); } public static Complex operator +(Complex zst) { return new Complex(zst.x, zst.y); } public static Complex operator -(Complex zst, Complex zdr) { return new Complex(zst.x - zdr.x, zst.y - zdr.y); } public static Complex operator -(Complex zst) { return new Complex(-zst.x, -zst.y); } public static Complex operator *(Complex zst, Complex zdr) { return new Complex(zst.x * zdr.x - zst.y * zdr.y, zst.y * zdr.x + zst.x * zdr.y); } public static Complex operator /(Complex zst, Complex zdr) { double r = zdr.Ro2; return new Complex((zst.x * zdr.x + zst.y * zdr.y) / r, (zst.y * zdr.x - zst.x * zdr.y) / r); } public static implicit operator Complex(double x) { return new Complex(x, 0); } public static bool operator ==(Complex zst, Complex zdr) { return (zst - zdr).Ro2 < 1.0e-12; } public static bool operator !=(Complex zst, Complex zdr) { return (zst - zdr).Ro2 >= 1.0e-12; } public override bool Equals(object o) { if (o.GetType() != this.GetType()) return false; else return this == (Complex)o; } public override int GetHashCode() {

11

} }

return 0;

public class NodCom //noduri pentru o lista de numere complexe { public Complex z; public NodCom next; public NodCom() { z = new Complex(); next = null; } public NodCom(NodCom p) //constructorul de copiere { this.z = p.z; this.next = p.next; } public NodCom(Complex z) { this.z = z; //nu este nevoie de copiere, //Complex este o structura this.next = null; } public NodCom(double xx, double yy) { this.z = new Complex(xx, yy); this.next = null; } } public class ListaCom { // // Lista simplu inlantuita cu noduri de tip NodCom

public NodCom primulNod; private NodCom ultimulNod; public ListaCom() { primulNod = null; ultimulNod = null; } public ListaCom(ListaCom li) //Constructorul de copiere { primulNod = null; ultimulNod = null; for (NodCom p = li.primulNod; p != null; p = p.next) { this.adaugaNod(p); } } public void adaugaNod(NodCom p) {

12

NodCom pp = new NodCom(p); //copiem nodul primit if (primulNod == null) ultimulNod = primulNod = pp; //initiere lista else ultimulNod = ultimulNod.next = pp; //continuare lista } public void adaugaNod(Complex z) { NodCom p = new NodCom(z); if (primulNod == null) ultimulNod = primulNod = p; //initiere lista else ultimulNod = ultimulNod.next = p; //continuare lista } } }

3. Fiierul FractalForm.cs
using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms;

namespace FractalExplorer { public partial class FractalForm : Form { protected Bitmap bmp; protected Color[] paleta; protected Color penColor; protected const int dimPaleta=1024; protected const int dimPicBox=602; protected const int dimPicBmp = 600; protected int imax, imin, jmax, jmin; protected double xmax, xmin, ymax, ymin; protected double dxdi, dydj, didx, djdy; protected bool doWork; public FractalForm() { InitializeComponent(); this.Height = dimPicBox+70; this.Width = dimPicBox+30; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.ClientSize = new System.Drawing.Size(dimPicBox+24, dimPicBox+38);

13

this.picBox.Location = new System.Drawing.Point(12, 26); this.picBox.Size = new System.Drawing.Size(dimPicBox, dimPicBox); this.picBox.BackColor = Color.Black; this.mainMenu.Location = new System.Drawing.Point(0, 0); this.mainMenu.Size = new System.Drawing.Size(dimPicBox+24, 24); imin = 0; imax = dimPicBmp-1; jmin = 0; jmax = dimPicBmp-1; setXminXmaxYminYmax(0.0, 1.0, 0.0, 1.0); makeTitle(); } public virtual void makeTitle() { this.Text = "No title"; MessageBox.Show("Metoda \"makeTitle()\" trebuie suprascrisa."); } public virtual void makeImage() { } MessageBox.Show("Metoda \"makeImage()\" trebuie suprascrisa.");

private void FractalForm_Load(object sender, EventArgs e) { bmp = new Bitmap(dimPicBmp, dimPicBmp, System.Drawing.Imaging.PixelFormat.Format24bppRgb); bmp.SetResolution(300F, 300F); this.startToolStripMenuItem.Enabled = true; this.stopToolStripMenuItem.Enabled = false; this.saveToolStripMenuItem.Enabled = false; penColor = Color.White; paleta = new Color[dimPaleta]; for (int k = 0; k < dimPaleta; k++) { double tcol = 56.123 + 2.0 * Math.PI * k / (double)dimPaleta; int rcol = (int)(128 + 128 * Math.Sin(tcol)); int gcol = (int)(128 + 128 * Math.Sin(2 * tcol)); int bcol = (int)(128 + 128 * Math.Cos(3 * tcol)); paleta[k] = Color.FromArgb(rcol % 256, gcol % 256, bcol % 256); } } private void picBox_VisibleChanged(object sender, EventArgs e) { picBox.Image = bmp; } private void startToolStripMenuItem_Click(object sender, EventArgs e) { this.startToolStripMenuItem.Enabled = false; this.stopToolStripMenuItem.Enabled = true; this.saveToolStripMenuItem.Enabled = false; doWork = true;

14

initScreen(); makeImage(); this.startToolStripMenuItem.Enabled = true; this.stopToolStripMenuItem.Enabled = false; this.saveToolStripMenuItem.Enabled = true;

private void stopToolStripMenuItem_Click(object sender, EventArgs e) { doWork = false; this.startToolStripMenuItem.Enabled = true; this.stopToolStripMenuItem.Enabled = false; this.saveToolStripMenuItem.Enabled = true; } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { doWork = false; bmp.Dispose(); this.Close(); } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { doWork = false; this.startToolStripMenuItem.Enabled = true; this.stopToolStripMenuItem.Enabled = false; mySaveFileDialog.Filter = "bitmap files (*.bmp)|*.bmp"; if (mySaveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK && mySaveFileDialog.FileName.Length > 0) { bmp.Save(mySaveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp); } } private void FractalForm_FormClosing(object sender, FormClosingEventArgs e) { doWork = false; bmp.Dispose(); } protected void initScreen() { bmp.Dispose(); bmp = new Bitmap(dimPicBmp, dimPicBmp, System.Drawing.Imaging.PixelFormat.Format24bppRgb); bmp.SetResolution(300F, 300F); picBox.Image = bmp; Application.DoEvents();

15

} protected bool resetScreen() { picBox.Invalidate(); Application.DoEvents(); return doWork; } protected void delaySec(double s) { DateTime d = DateTime.Now; while ((DateTime.Now - d).TotalSeconds < s) Application.DoEvents(); } protected void setXminXmaxYminYmax(double xm, double XM, double ym, double YM) { xmin = xm; xmax = XM; ymin = ym; ymax = YM; dxdi = (xmax - xmin) / (imax - imin); dydj = (ymax - ymin) / (jmax - jmin); didx = (imax - imin) / (xmax - xmin); djdy = (jmax - jmin) / (ymax - ymin); } public public public public public int getI(double x) { return (int)(imin + (x - xmin) * int getJ(double y) { return (int)(jmin + (y - ymin) * double getX(int i) { return xmin + (i - imin) * dxdi; double getY(int j) { return ymin + (j - jmin) * dydj; Complex getZ(int i, int j){ return new Complex(xmin + imin) * dxdi,ymin + (j - jmin) * dydj);} public Color getColor(int k) { return paleta[k % dimPaleta]; protected void setPixel(int i, int j, Color c) { if (i < imin || imax < i || j < jmin || jmax < j) return; bmp.SetPixel(i, jmax - j, c); } protected void setPixel(double x, double y, Color c) { setPixel((int)(imin + (x - xmin) * didx), (int)(jmin + (y - ymin) * djdy), c); } protected void setPixel(Complex z, Color c) { setPixel((int)(imin + (z.x - xmin) * didx), (int)(jmin + (z.y ymin) * djdy), c); } protected void setLine(int i0, int j0, int i1, int j1, Color c) { int i,j,dir; didx); } djdy); } } } (i }

16

double m; //linie verticala: if (i0 == i1) { if (j0 <= j1) { for (j = j0; j <= j1; j++) setPixel(i0, j, c); } else { for (j = j1; j <= j0; j++) setPixel(i0, j, c); } return; } //linie orizontala sau oblica: m = (double)(j1 - j0) / (double)(i1 - i0); if (-1<=m && m<=1) { dir=(i0<i1 ? +1 : -1); i = i0; while (i != i1) { setPixel(i, (int)Math.Round(j0 + m * (i - i0)), c); i += dir; } } else //m<-1 || m>1 { dir = (j0 < j1 ? +1 : -1); j = j0; while (j != j1) { setPixel((int)Math.Round(i0 + (j - j0) / m), j, c); j += dir; } } setPixel(i1, j1, c); return; } protected void setLine(double x0, double y0, double x1, double y1, Color c) { setLine((int)(imin + (x0 - xmin) * didx), (int)(jmin + (y0 ymin) * djdy), (int)(imin + (x1 - xmin) * didx), (int)(jmin + (y1 - ymin) * djdy), c); } protected void setLine(Complex z0, Complex z1, Color c) { setLine((int)(imin + (z0.x - xmin) * didx), (int)(jmin + (z0.y ymin) * djdy),

17

(int)(imin + (z1.x - xmin) * didx), (int)(jmin + (z1.y ymin) * djdy), c); } protected void setAxis() { setLine(xmin, 0.0, xmax, 0.0, penColor); setLine(0.0, ymin, 0.0, ymax, penColor); } private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { AboutForm aboutForm = new AboutForm(); aboutForm.ShowDialog(); } } }

4. Fiierul FractalForm.Designer.cs
namespace FractalExplorer { partial class FractalForm { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// /// /// /// <summary> Clean up any resources being used. </summary> <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.picBox = new System.Windows.Forms.PictureBox(); this.mainMenu = new System.Windows.Forms.MenuStrip();

18

this.menuToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.startToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.stopToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mySaveFileDialog = new System.Windows.Forms.SaveFileDialog(); this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize) (this.picBox)).BeginInit(); this.mainMenu.SuspendLayout(); this.SuspendLayout(); // // picBox // this.picBox.BackColor = System.Drawing.Color.Black; this.picBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.picBox.Location = new System.Drawing.Point(12, 26); this.picBox.Name = "picBox"; this.picBox.Size = new System.Drawing.Size(600, 600); this.picBox.TabIndex = 0; this.picBox.TabStop = false; this.picBox.VisibleChanged += new System.EventHandler(this.picBox_VisibleChanged); // // mainMenu // this.mainMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.menuToolStripMenuItem}); this.mainMenu.Location = new System.Drawing.Point(0, 0); this.mainMenu.Name = "mainMenu"; this.mainMenu.Size = new System.Drawing.Size(624, 24); this.mainMenu.TabIndex = 1; this.mainMenu.Text = "menu1"; // // menuToolStripMenuItem // this.menuToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.startToolStripMenuItem, this.stopToolStripMenuItem, this.saveToolStripMenuItem, this.aboutToolStripMenuItem, this.exitToolStripMenuItem}); this.menuToolStripMenuItem.Name = "menuToolStripMenuItem"; this.menuToolStripMenuItem.Size = new System.Drawing.Size(45, 20); this.menuToolStripMenuItem.Text = "&Menu"; //

19

// startToolStripMenuItem // this.startToolStripMenuItem.Name = "startToolStripMenuItem"; this.startToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.startToolStripMenuItem.Text = "&Start"; this.startToolStripMenuItem.Click += new System.EventHandler(this.startToolStripMenuItem_Click); // // stopToolStripMenuItem // this.stopToolStripMenuItem.Name = "stopToolStripMenuItem"; this.stopToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.stopToolStripMenuItem.Text = "Sto&p"; this.stopToolStripMenuItem.Click += new System.EventHandler(this.stopToolStripMenuItem_Click); // // saveToolStripMenuItem // this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.saveToolStripMenuItem.Text = "Sa&ve"; this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); // // aboutToolStripMenuItem // this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; this.aboutToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.aboutToolStripMenuItem.Text = "&About"; this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; this.exitToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.exitToolStripMenuItem.Text = "E&xit"; this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // // FractalForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(624, 638); this.Controls.Add(this.picBox); this.Controls.Add(this.mainMenu); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;

20

this.MainMenuStrip = this.mainMenu; this.MaximizeBox = false; this.Name = "FractalForm"; this.Text = "No title"; this.Load += new System.EventHandler(this.FractalForm_Load); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FractalForm_FormClosing); ((System.ComponentModel.ISupportInitialize) (this.picBox)).EndInit(); this.mainMenu.ResumeLayout(false); this.mainMenu.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion protected System.Windows.Forms.PictureBox picBox; private System.Windows.Forms.MenuStrip mainMenu; private System.Windows.Forms.ToolStripMenuItem menuToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem startToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem stopToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; private System.Windows.Forms.SaveFileDialog mySaveFileDialog; private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;

} }

5. Fiierul Program.cs
using using using using using using System; System.Collections.Generic; System.Linq; System.Drawing; System.Windows.Forms; System.Threading;

namespace FractalExplorer { public class Sablon : FractalForm { /*public override void makeTitle() { this.Text = "SABLON"; }*/ public override void makeImage() { setXminXmaxYminYmax(-10, 20, -10, 20); setAxis(); double ro, theta; Complex z0,a,i=new Complex(0,1);

21

Color col; z0 = 5+5*i; a=Complex.setRoTheta(0.99, Math.PI/24); ListaCom oldList = new ListaCom(); ListaCom newList = new ListaCom(); for (theta = 0, ro=7; theta < 2 * Math.PI; theta += 0.01) { oldList.adaugaNod(Complex.setRoTheta(ro, theta)); } for (int k = 0; k<500; k++) { col = getColor(100 + 2*k); for (NodCom p = oldList.primulNod; p != null; p = p.next) { setPixel(p.z, col); newList.adaugaNod( z0+a*(p.z-z0)); } oldList=newList; newList = new ListaCom(); if (!resetScreen()) return; //delaySec(0.2); } } } static class Program { [STAThread] static void Main() { Application.Run(new Sablon()); } } }

22