Literatura: do wykładu - dowolny podręcznik do języka C++ na laboratoriach - Borland C++ Builder S. Lippman Podstawy języka C++ K. Jamsa Wygraj z C++ Bjarne Stroustrup Język C++ - ksiąŝka napisana przez twórcę C++ Robert Sedgewick Algorytmy w C ++ Jerzy Grębosz Symfonia C++ Andrzej Stasiewicz C++ Builder Symulacje komputerowe Kent Reisdorph C++ Builder 6 dla kaŝdego laboratorium S. Prata Szkoła programowania, Język C++ Programowanie obiektowe umoŝliwia spójne przedstawienie systemu poprzez stworzenie typów danych, które są tak samo wygodne w uŝyciu, jak typy danych wbudowane w język programowania. Siłą metod obiektowych jest moŝliwość ponownego uŝycia kodu poprzez dziedziczenie i polimorfizm. Klasy pozwalają na wygodną i elegancką hermetyzację bytów programowych. Co jest dobrą klasą? Dobrze napisana klasa ma dobrze zdefiniowany zbiór operacji. Na dobrze napisaną klasę moŝna patrzeć jak na czarną skrzynkę manipulowaną wyłącznie za pomocą tego zbioru operacji. Rzeczywistą reprezentację klasy moŝna zmodyfikować, nie wpływając na sposób uŝywania tego zbioru operacji. Komponent Jednostka montaŝowa z wyspecyfikowanymi interfejsami, oraz jawnymi zaleŝnościami kontekstowymi. Jest modułem binarnym (nie kodem źródłowym), z kontraktowo opisanymi interfejsami i podanymi wprost zaleŝnościami. Opublikowany interfejs to wszystkie informacje, z których moŝna korzystać w celu komunikacji z komponentem. Komponent nie sprawuje kontroli nad sobą - moŝe być uŝyty przez inne elementy programu - posiada pełną specyfikację zaleŝności - specyfikuje oferowaną przez siebie funkcjonalność - moŝe być uŝyty wyłącznie na podstawie tej specyfikacji Programowanie komponentowe - łączymy komponenty z naszymi obiektami - komponenty mogą jedynie wspomóc tworzenie zadanego typu aplikacje. Przykłady opisu naszych obiektów które mogą wspomagać kilka projektów. skala.h skala.cpp widmo.h widmo.cpp Helion Andrzej Stasiewicz C++ Builder Symulacje komputerowe W przedstawionych przykładach obiekty klasy TSkalowanie budujemy zgodnie z konstruktorem TSkalowanie obiekt1 ( int xe0, int ye0, int eszer, int ewys, double xr0, double yr0, double rszer, double rwys); xe0, ye0 - lewy górny róg obszaru ekranowego, eszer, ewys - szerokość i wysokość obszaru ekranowego xr0, yr0 - środek obszaru rzeczywistego, rszer, rwy szerokość i wysokość obszaru rzeczywistego 1
#ifndef skalah #define skalah /*********************************************************************** ** Programowanie komponentowe - Jan Kowalski ** ** "skala.h" ** ** Zawartosc: ** ** Skalowanie obszaru ekranowego w matematyczny i odwrotnie ** ** Współrzędne punktu (x,y) z obszaru "rzeczywistego" po skalowaniu ** ** wpisane są na ekran. Współczynnki skalowania spełniają zależność ** ** A B C D A*X+B, C*Y+D ** ** Historia: ** ** Wersja Data Zmiany Autor/Programista ** ** 1.00 C++Buider (Symulacje komp.) Stasiewicz Andrzej ** ** 1.01 2010/03/06 rzutowanie static_cast<double> EK ** ***********************************************************************/ class TSkalowanie private: double A, B, C, D; //wspolczynniki skalowania rzeczywistosc - ekran double E, F, G, H; //wspolczynniki skalowania ekran - rzeczywistosc public: TSkalowanie(int xe0, int ye0, int eszer, int ewys, double xr0, double yr0, double rszer, double rwys); //Konstruktor - // xe0, ye0 - lewy górny róg obszaru ekranowego, // eszer, ewys - szerokosc i wysokosc obszaru ekranowego // xr0, yr0 - srodek obszaru rzeczywistego, // rszer, rwys - szerokosc i wysokosc obszaru rzeczywistego double Daj_real_x( int xe); //Wyliczenie wspolrzednej rzeczywistej dla wspolrzednej ekranowej xe double Daj_real_y( int ye); //Wyliczenie wspolrzednej rzeczywistej dla wspolrzednej ekranowej ye int Daj_ekr_x( double xr); //Wyliczenie wspolrzednej ekranowej xe dla wspolrzednej rzeczywistej xr int Daj_ekr_y( double yr); //Wyliczenie wspolrzednej ekranowej ye dla wspolrzednej rzeczywistej yr ; #endif Zwracam się z prośbą do Państwa proszę zachować ten sposób dokumentowania klas w oddawanych na zaliczenie projektach (czytelność łatwość budowania obiektów). 2
#ifndef widmoh #define widmoh ************************************************************************ ** Programowanie komponentowe - Jan Kowalski ** ** "widmo.h" ** ** Zawartosc: ** ** Obiekt konstruuje kolor odpowiadajacy fizycznej barwie. ** ** Algorytm przelicza okreslona dlugosc fali swiatla (barwa fizyczna) ** ** w skladniki koloru RGB. Obiekt przechowuje dane o kolorze ** ** kilkunastu wybranych dlugosci fal. Kolory posrednie sa wyliczane ** ** metoda przyblizenia liniowego. ** ** Jasnosc swiatla zadawana procentowo (od 0 do 100) ** ** Historia: ** ** Wersja Data Zmiany Autor/Programista ** ** 1.00 C++Builder (Symulacje komp) Stasiewicz Andrzej** ** 1.01 2010/03/06 rzutowanie static_cast<double> EK ** ***********************************************************************/ class TWidmo private: int tecza[ 15][ 3]; // punkty teczy na RGB double Askal, Bskal, Cskal; //wspolczynniki skalujace public: double LAMBDA_MIN, LAMBDA_MAX; TWidmo( void); //konstruktor TColor Lambda_to_kolor( int jasnosc, double L); //Funkcja zamieniajaca dlugosc i jasnosc w kolor (pseudolosowe rozmywanie //barwy i jasnosci ; #endif Budujemy obiekt zgodnie z zaplanowanym konstruktorem Implementacja metod klasy TSkalowanie TWidmo obiekt2; #include "skala.h" TSkalowanie::TSkalowanie(int xe0, int ye0, int eszer, int ewys, double xr0, double yr0, double rszer, double rwys) A = static_cast<double> (eszer)/rszer; B = static_cast<double> (xe0)-a*(xr0-rszer/2.0); C = -static_cast<double>(ewys)/rwys; D = static_cast<double> (ye0)-c*(yr0+rwys/2.0); 3
E=rszer/static_cast<double>(eszer); //z ekranu do przestrzeni F=xr0-rszer/2.0-E*static_cast<double>(xe0); G=-rwys/static_cast<double>(ewys); H=yr0+rwys/2.0-G*static_cast<double>(ye0); //---------------------------------------------------- int TSkalowanie::Daj_ekr_x(double xr) return static_cast<int>(a*xr+b); //---------------------------------------------------- int TSkalowanie::Daj_ekr_y(double yr) return static_cast<int>(c*yr+d); //---------------------------------------------------- double TSkalowanie::Daj_real_x(int xe) return E*xe+F; //---------------------------------------------------- double TSkalowanie::Daj_real_y(int ye) return G*ye+H; // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Implementacja metod klasy TWidmo //---- widmo.cpp ---------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "widmo.h" #include <stdlib.h> //--------------------------------------------------------------------------- TWidmo :: TWidmo( void) int il_czysty_kolor = 15; // zadana liczba wejsc do tabeli tecza LAMBDA_MIN = 0.35E-6; //dolna granica swiatla widzialnego - fioletowa LAMBDA_MAX = 0.7E-6; //gorna granica swiatla widzialnego - czerwona Askal = static_cast<double>(il_czysty_kolor-1) / (LAMBDA_MAX - LAMBDA_MIN); Bskal = -Askal * LAMBDA_MIN; Cskal = 4. / 100.; //skalowanie jasnosci tecza[0][0] = 30; tecza[0][1] = 7; tecza[0][2] = 40; tecza[1][0] = 40; tecza[1][1] = 10; tecza[1][2] = 50; tecza[2][0] = 47; tecza[2][1] = 15; tecza[2][2] = 63; tecza[3][0] = 23; tecza[3][1] = 31; tecza[3][2] = 63; tecza[4][0] = 0; tecza[4][1] = 40; tecza[4][2] = 63; tecza[5][0] = 0; tecza[5][1] = 53; tecza[5][2] = 50; tecza[6][0] = 0; tecza[6][1] = 63; tecza[6][2] = 20; tecza[7][0] = 31; tecza[7][1] = 63; tecza[7][2] = 0; tecza[8][0] = 63; tecza[8][1] = 63; tecza[8][2] = 0; tecza[9][0] = 63; tecza[9][1] = 47; tecza[9][2] = 7; 4
tecza[10][0] = 63; tecza[10][1] = 31; tecza[10][2] = 15; tecza[11][0] = 63; tecza[11][1] = 15; tecza[11][2] = 7; tecza[12][0] = 63; tecza[12][1] = 0; tecza[12][2] = 0; tecza[13][0] = 51; tecza[13][1] = 0; tecza[13][2] = 0; tecza[14][0] = 40; tecza[14][1] = 0; tecza[14][2] = 0; //--------------------------------------------------------- TColor TWidmo :: Lambda_to_kolor( int jasnosc, double L) int pierwszy_kolor, r, g, b; double prawdziwy_kolor, ulamek_drugiego, a1, a2; double jasn; jasnosc += (1.0-random(3)); L += 0.1E-8*(1.0-static_cast<double>(random(2000))/1000.0); if(l<=lambda_min L>=LAMBDA_MAX) return clblack; //poza zakresem widzenia if(jasnosc > 100) jasnosc=100; if(jasnosc < 0) jasnosc=0; jasn=cskal*jasnosc; //zbyt duza jasnosc //zbyt mala jasnosc //przeskalowanie jasnosci prawdziwy_kolor=askal*l+bskal; pierwszy_kolor=static_cast<int > (prawdziwy_kolor); //czesc calkowita np. 7 ulamek_drugiego=prawdziwy_kolor-pierwszy_kolor; //ulamek 2 koloru np. 0.35 a1=tecza[pierwszy_kolor][0]*jasn; a2=tecza[pierwszy_kolor+1][0]*jasn; r=static_cast<int>(a1+ulamek_drugiego*(a2-a1)); a1=tecza[pierwszy_kolor][1]*jasn; a2=tecza[pierwszy_kolor+1][1]*jasn; g=static_cast<int>(a1+ulamek_drugiego*(a2-a1)); a1=tecza[pierwszy_kolor][2]*jasn; a2=tecza[pierwszy_kolor+1][2]*jasn; b=static_cast<int>(a1+ulamek_drugiego*(a2-a1)); return RGB(r,g,b); Przykład 1 wykreślenie widma światła białego tworzymy obiekty klas: TSkalowanie, TWidmo, rysowanie - FormPain - wykorzystujemy Canvas. Canvas "płótno" powierzchnia do rysowania, obszar roboczy formularza. Obiekt klasy Canvas ( z bibloteki VCL Borlanda) słuŝy do ułatwienia rysowania grafiki (punktów, figur geometrycznych) w oknie komponentów TForm lub TImage. Canvas nie posiada własnej kontrolki na palecie komponentów void fastcall TForm1::FormPain(TObject *Sender) int marg = 10; //margines int xe, ye; //wspólrzedne ekranowe piksela 5
double lambda; //dlugosc fali int jasn; //jasnosc swiatla TWidmo w; // obiekt w klasy TWidmo TSkalowanie s(marg,marg,clientwidth-2*marg,clientheight-2*marg, (w.lambda_max+w.lambda_min)/2.0,50, w.lambda_max-w.lambda_min,100); //obiekt s klasy TSkalowanie for(xe=marg;xe < ClientWidth-marg;xe++) for(ye=marg;ye < ClientHeight-marg;ye++) lambda=s.daj_real_x(xe); //wywołana metoda klasy TSkalowanie jasn=s.daj_real_y(ye); //wywołana metoda klasy TSkalowanie Canvas -> Pixels[xe][ye] = w.lambda_to_kolor(jasn,lambda); //wywołana metoda klasy TWidmo Przykład 2 - Liść paproci algorytm sparametryzowany zamknięty w pętli. Tworzymy obiekt klasy TSkalowanie, rysujemy na "płótnie" Canvas void TForm1::Lisc_paproci(void) int nr_p; const double A[] = 0.0, 0.85, 0.2, -0.15, B[] = 0.0, 0.04,-0.26, 0.28, C[] = 0.0,-0.04, 0.23, 0.26, D[] = 0.16,0.85, 0.22, 0.24, E[] = 0.0, 0.0, 0.0, 0.0, F[] = 0.0, 1.6, 1.6, 0.44; 6
TSkalowanie skal(150,150,clientwidth/2,clientheight/2,0,4,5,10); // wywolanie obiektu do namalowania liscia paproci buton TSkalowanie lisc paproci double x,y,x1; int xe,ye; int p[4]=1,79,10,10; x=0;y=0; for(long int i=0;i<150000;i++) nr_p=n_random(p,4); x1=a[nr_p]*x+b[nr_p]*y+e[nr_p]; y=c[nr_p]*x+d[nr_p]*y+f[nr_p]; x=x1; xe=skal.daj_ekr_x(x); ye=skal.daj_ekr_y(y); Canvas->Pixels[xe][ye]=clGreen; int TForm1::n_random(int *p,int n) int a,sum=0,sum_w=0; int z; for(int i=0;i<n;i++) sum_w+=p[i]; a=random(sum_w); for(z=0;z<n;z++) sum+=p[z]; if(a<sum) break; return z; 7
Trzy instancje TSkalowanie - kaŝda z trzech instancji przenosi na ekran współrzędne Wybrane właściwości TCanvas Nazwa Znaczenie - zastosowanie / przykładowe wartości Pixels dwuwymiarowa tablica. TColor Pixels [int X]int Y] umoŝliwia dostęp (zapis i odczyt) koloru pojedynczych pikseli w oknie Pen definiuje właściwości konturu (linii) rysowanych obiektów ->Color = kolor linii np. clblue, clred ->Width= grubośc linii w pikselach np.3 ->Style = styl linii np. pssolid, psdot Brush definiuje właściwości wypełniania rysowanych obiektów -> Color = kolor wypełnienia np.clblue, clred ->Style = styl wypełnienia np. pssolid, psdot Wybrane metody TCanvas Nazwa Znaczenie - zastosowanie / przykładowe wartości Arc Wykreśla łuk okręgu, uŝywają aktualnie wybranego pióra. Łuk jest fragmentem elipsy ograniczonej zadanym prostokątem Ellipse Rysuje elipsę wpisaną w prostokąt o zadanych wierzchołkach Canvas ->Ellipse(100,100,200,200); LineTo Rysuje linię od aktualnej pozycji kursora graficznego do punktu o zadanych współrzędnych (X,Y) MoveTo Przesuwa kursor graficzny do punktu o zadanych współrzędnych (bez rysowania linii) Pie Rysuje wycinek koła Rectangle Wykreśla prostokąt którego przeciwległymi wierzchołkami są zadane punkty o współrzędnych (X1,Y1) oraz (X2,Y2). RoundRect Wykreśla prostokąt o zaokrąglonych naroŝnikach TextOut Wypisuje na powierzchni "płótna" zadany tekst rozpoczynając od punktu o zadanych współrzędnych (X,Y). 8
Przykład 3 składanie drgań tworzymy 3 obiekty klasy TSkalowanie + 6 komponentów TrackBar - wykorzystujemy Canvas. void fastcall TForm1::FormShow(TObject *Sender) TrackBar1Change( Sender); //zainicjuj parametry fal TrackBar2Change( Sender); TrackBar3Change( Sender); TrackBar4Change( Sender); TrackBar5Change( Sender); TrackBar6Change( Sender); //--------------------------------------------------------------------------- void fastcall TForm1::FormPaint(TObject *Sender) int xe1_old, ye1_old, xe2_old, ye2_old, xe3_old, ye3_old; //wspolrzedne ekranowe int xe1, ye1, xe2, ye2, xe3, ye3; //wspolrzedne ekranowe double x, y1, y2, y3; //wspolrzedne rzeczywiste double k1, k2; //parametry pomocnicze bool pierwszy = true; int a = ClientHeight / 4; //pomocnicze TSkalowanie s1( Panel1-> Width, 0, ClientWidth -Panel1 ->Width, a, 0, 0, 20, 10); TSkalowanie s2( Panel1 -> Width, a, ClientWidth - Panel1 -> Width, a, 0, 0, 20, 10); TSkalowanie s3( Panel1 -> Width,2a, ClientWidth - Panel1 -> Width,2a, 0, 0, 20, 20); k1 = 2 * M_PI / L1; k2 = 2 * M_PI / L2; Canvas -> Pen -> Width = 2; for( x = -10; x < 10; x += 0.1) y1 = A1 * sin( k1 * x + f1); xe1 = s1.daj_ekr_x( x); ye1 = s1.daj_ekr_y( y1); //pierwszy przebieg A amplituda L długość F faza 9
Komponenty + nasz obiekt Dziedziczenie Klasy pochodne są prostym elastycznym i efektywnym mechanizmem definiowania klasy przez dodawanie udogodnień do istniejącej klasy, bez ponownego programowania. #ifndef diagramh #define diagramh #include "skala.h" /*********************************************************************** ** Programowanie komponentowe - Jan Kowalski ** ** "diagram.h" ** ** Zawartosc: ** ** Wykreslenie siatki wspolrzednych ** ** Historia: ** ** Wersja Data Zmiany Autor/Programista ** ** 1.00 C++Buider (Symulacje komp.) Stasiewicz Andrzej ** ** 1.01 2010/03/15 tylko siatki bez układu współ. EK ** ***********************************************************************/ class TDiagram : public TSkalowanie private: TCanvas *canvas; double xr0, yr0, rszer, rwys; 10
public: TDiagram( int xe0, int ye0, int eszer, int ewys,double Axr0, double Ayr0, double Arszer, double Arwys,TCanvas *Acanvas); void Siatka( double x0, double y0, double x1, double x2, double y1, double y2, double dx, double dy, TColor kolor=clgray); // (x0, y0) - srodek ukladu wspolrzednych // (x1 - x2) - rozpietosc osi X // (y1 - y2) - rozpietosc osi Y // dx, dy - rozmiary oczka siatki // kolor - kolor grafiki void Siatka( double x0, double y0, double dx, double dy, TColor kolor=clgray); void Siatka( double dx, double dy, TColor kolor=clgray); ; #endif Przykład 4 Wykreślenie widma światła białego + siatka w celu np. odczytania długości fali o zadanej barwie. Tworzymy obiekty klas: TDiagram d - obiekt dziedziczy atrybuty i metody klasy TSkalowanie a takŝe posiada własne atrybuty i metody niezbędne do narysowania siatki. TWidmo w rysowanie - FormPain - wykorzystujemy Canvas. void fastcall TForm1::FormPaint(TObject *Sender) int marg = 10; //margines int xe, ye; //wspólrzedne ekranowe piksela double lambda; //dlugosc fali int jasn; //jasnosc swiatla TWidmo w; TDiagram d( marg, marg, ClientWidth-2*marg, ClientHeight-2*marg, (w.lambda_max+w.lambda_min)/2., 75, w.lambda_max-w.lambda_min, 50, Canvas); for( xe=marg; xe < ClientWidth-marg; xe++) for( ye=marg; ye < ClientHeight-marg; ye++) lambda = d.daj_real_x( xe); //wywołana metoda z klasy bazowej jasn = d.daj_real_y( ye); Canvas -> Pixels[xe][ye] = w.lambda_to_kolor( jasn, lambda); d.siatka( (w.lambda_max-w.lambda_min)/10., 5, clwhite); 11
12