Documente Academic
Documente Profesional
Documente Cultură
Elemente de grafică în C
I. Moduri video
Un număr ridicat de funcţii predefinite video din fişierul antet conio.h şi din biblioteca
graphics.lib definesc posibilităţi semnificative pentru utilizarea ecranului în cercetare şi
proiectare, în prognozare sau chiar în scopuri comerciale, sub forma clipurilor. În funcţie
de destinaţia lor, acestea pot fi împărţite în mai multe categorii, astfel: iniţializare şi
instalare mod grafic, tratare erori grafice, desenare linii, trasare cercuri, arcuri şi alte
curbe, desenare poligoane şi haşurări, desenare puncte, scriere texte grafice, salvare
imagini, definire culori şi definire şi utilizare de ferestre şi de pagini.
Pe de o parte, în configuraţiile hardware ale calculatoarelor compatibile IBM PC intervin
monitoare de diverse tipuri (monocolor, color sau color extins), iar pe de alta,
comunicarea dintre microprocesorul şi monitorul unui calculator nu se face direct, ci prin
intermediul memoriei video (memoriei ecran), care se află pe placa adaptorului video
(adaptorului grafic), aşa numita placă video (placă grafică, cartelă video, cartelă grafică).
Un program de interfaţă (un driver grafic) cu extensia .BGI (Borland Graphics Interface),
specific adaptorului folosit, permite controlul interfeţei între funcţiile video prin care
microprocesorul depune în memoria video semnale care reprezintă texte şi imagini şi
facilităţile oferite de adaptorul grafic, prin care monitorul îşi extrage continuu date din
memoria video şi le trimite pe ecran.
Dintre cele mai des întîlnite adaptoare video se enumeră: CGA (Color Graphics
Adapter), MCGA ( MultiColor Graphics Adapter), EGA (Enhanced Graphics Adapter),
EGA64, EGAMono, IBM8514, HGA (Hercules Graphics Adapter), ATT, VGA (Video
graphics Array) şi PC3270. Aproape toate adaptoarele grafice pot fi comutate în modurile
Hercules, VGA şi EGA, care este şi cel mai vechi. Spre exemplu, adaptoarele grafice
EGA şi VGA sînt controlate de driver-ul egavga.bgi. Pentru adaptorul color adresa
de început a memoriei ecran este la 0xB800:0, iar pentru cel monocolor la 0xB000:0.
Programul 14.1.1 interoghează calculatorul asupra tipului adaptorului video. Rezultatul
furnizat a fost adresa 0xB800, adică calculatorul pe care s-a rulat acest program are un
adaptor video color.
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <stdlib.h>
int placa(void)
void main()
{ long incepecran;
clrscr();
placa;
printf("incepecran = %0x", incepecran);
getch(); }
int placa(void);
int driver, modus;
1
driver=DETECT;
detectgrapf(driver, modus);
printf("Driver-ul grafic are numarul:%d", driver);
switch (driver)
{ case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 8:
case 9: incepecran = 0xb800;
break;
case -2:
case 7:
case 10: incepecran = 0xb000;
break;
}
return incepecran; }
Programul 14.1.1
2
înseamnă că este nevoie de multă memorie, adică 348x90=31320 octeţi sau 32ko per
pagina de ecran. Înălţimea unui rînd de ecran este de un pixel, pe cînd în modul text este
de 8 sau 9 pixele. Grafica în culori, în schimb, necesită mai multă memorie. Cu un bit de
pixel pot fi reprezentate maxim două culori, cu doi biţi de pixeli cel mult patru culori,
numărul biţilor crescînd rapid în funcţie de numărul culorilor folosite. Zona de memorie
necesară se alocă din RAM-ul adaptorului grafic, deoarece în memoria ecran operativă au
loc doar două pagini de ecran la adresele 0xB000:0 şi respectiv 0xB800:0. De exemplu,
codificarea numerică a paletei de culori implicită pentru VGA: black, blue, green, cyan,
red, magenta, brown, white, gray, light_blue, light_green, light_cyan, light_red,
light_magenta, yellow, light_white, în ordine, este precizată în lista (0, 1, 2, 3, 4, 5, 20, 7,
56, 57, 58, 59, 60, 61, 62, 63). Culoarea de fond (background) este 0, iar culoare cernelii
(foreground) este 63. Indicele culorii din paletă se denumeşte prin valoare pixel.
Un concept comun celor două stiluri de lucru îl reprezintă fereastra, care se
defineşte prin porţiunea rectangulară de ecran activă la un moment dat. Fereastra poartă
denumirea de window pentru modul grafic şi viewport pentru modul grafic. Fereasatra
implicită se consideră întreg ecranul. Scrierea textelor sau desenarea imaginilor se face
în fereastra curentă, restul ecranului rămînînd nefolosit. Conţinutul ecranului se poate
organiza pe mai multe pagini de ecran complete sau numai pe porţiuni de ecran, care pot
fi salvate temporar în memoria RAM şi care pot fi apelate succesiv într-un timp scurt,
încît să nu se obsrve trecerea de la o pagină la alta.
Placa video şi monitorul pot fi trecute automat la oricare mod în care a fost
realizat programul (modul text fiind implicit), atît la nivel PC/MS-DOS prin intermediul
funcţiilor realizate de programator, cît şi la nivel DOS SHELL cu ajutorul funcţiilor
predefinite video. Modul grafic de lucru, controlul memoriei video, utilizarea culorilor în
programe BIOS sau controlul aprinderii şi stingerii cursorului, cu toate că necesită un
efort şi cunoştinţe desebite, vor constitui, în cele ce urmează, subiectul unor programe
interesante.
3
textmode(BW80); şi textmode(2); se descriu rezultate egale, adică un mod text cu 25 de
rînduri, 80 de coloane şi afişarea textului în nuanţe de gri.
Denumire simbolică Codul Caracteristici
4
lungimea declarată a şirului de caractere. Lungimea maximă a şirului se înscrie la adresa
s[0] înainte de activarea funcţiei cgets(). Deci, dimensiunea şirului de caractere s[] trebuie
declarată cu trei octeţi mai mare decît lungimea maximă a acestuia. Rezultatul întors de
funcţie este adresa şirului de caractere, adică s+2.
La scriere, spre deosebire de funcţia puts(), nu se sare la linie nouă la întîlnirea secvenţei
‘\r\n’.
Formatarea datelor editate în fereastra curentă, la citire, se realizează cu funcţia cscanf(),
care are prototipul următor:
int cscanf(char *şir_de_formatare [, lista_adrese_variabile]);. În mod similar,
pentru scriere se uitlizează funcţia:
int cprintf(const char * şir_de_formatare, listă_valori_ieşire);.
(x2, y2)
Mutarea textului se face corect chiar dacă zonele sursă şi destinaţie se suprapun pe unele
porţiuni, coordonatele fiind relative la ecran, nu la fereastra curentă. Se semnalează
eroare dacă s-au precizat coordonate care nu se pot localiza în fereastra curentă. În
situaţia unui eşec funcţia returnează 0, altfel o valoare nenulă.
Schimbarea poziţiei cursorului pe suprafaţa ferestrei curente se realizează cu funcţia:
void gotoxy(int x, int y);. Se deplasează cursorul în poziţia de coordonate (x, y),
unde x este coloana, iar y linia. Activarea funcţiei nu are efect dacă una din coordonate
este în afara ferestrei curente.
Pentru aflarea coordonatelor poziţiei curente a cursorului sănt disponibile funcţiile int
wherex(void); şi int wherex(void);.
5
Ştergerea completă a informaţiilor existente în fereastra activă cu deplasarea cursorului în
colţul din stînga sus (1, 1) se face cu funcţia: void clrscr();. Funcţia clrscr() nu
absentează din programele prezentate în această lucrare.
6
LIGHTGRAY Gri deschis 7
DARKGRAY Gri închis 8
LIGHTBLUE Albastru deschis 9
LIGHTGREEN Verde deschis 10
LIGHTCYAN Cyan deschis 11
LIGHTRED Roşu deschis 12
LIGHTMAGENTA Magenta deschis 13
YELLOW Galben 14
WHITE Alb 15
BLINK Clipitor 128
Tabelul 14.8.1
Pentru claritatea programului se recomandă utilizarea constantelor simbolice, care sînt cu
efect egal, aşa cum s-a precizat în exemplul de la sfîrşitul paragrafului 6.1.1.1. Spre
exemplu, cu apelul textcolor(LIGHTRED); se optează pentu textul ce urmează să se
scrie să aibă caractere roşu deschis.
2) void textbackground(int culoare); precizează culoarea fondului.
Numai primele 7 valori din tabelul 6.1.1.6.1 pot fi folosite pentru stabilirea culorii
fondului.
3) void normalvideo(void); selectează un mod de scriere normal, adică cel
existent valabil pînă la acest punct.
4) void lowvideo(void); selectează un mod de scriere mai puţin luminos, adică
bitul 3 va fi completat cu 0.
5) void highvideo(void); selectează un mod de scriere cu intensitate sporită, cu
alte cuvinte înscrie în bitul 3 valoarea 1.
6) void textattr(int atribut); modifică întreg octetul atribut. Prin operaţii de
mascare convenabile, cu operatorii logici binari & (conjuncţie) şi | (disjuncţie), se poate
modifica atributul după necesităţi. Spre exemplu, cu aplelul textattr(BLINK | RED * 16 |
WHITE); se va tipări un text roşu clipitor pe fond alb.
Trasarea unui cadru drepunghiular simplu, care poate fi completat eventual cu o
tabelă de meniu, se realizează cu funcţia cadru. Ca rezultat al celor 4 apelări în
programul 14.8.1, pe ecran se obţine o schemă grafică de genul:
roşu deschis
cyan
galben
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
void cadru(int, int, int, int, int);
void main()
{ clrscr();
cadru(1, 2, 80, 5, 12);
cadru(1, 6, 80, 22, 14);
cadru(64, 8, 78, 10, 11);
cadru(67, 19, 78, 21, 11);
getch(); }
7
void cadru(int x1, int y1, int x2, int y2, int culoare)
{ unsigned char css=218, co=196, cds=191, cv=179, csj=192, cdj=217;
int i;
textcolor(culoare);
gotoxy(x1, y1); putch(css); /* Coltul stinga sus */
for( i = x1+1; i<=x2-1; ++i) putch(co); /* Linie orizontala superioara */
putch(cds); /* Coltul dreapta sus */
for( i = y1+1; i<=y2-1; ++i)
{ gotoxy(x1, i); putch(cv); /* Linie verticala stinga */
gotoxy(x2, i); putch(cv); /* Linie verticala dreapta */
}
gotoxy(x1, y2); putch(csj); /* Coltul stinga jos */
for( i = x1+1; i<=x2-1; ++i) putch(co); /* Linie orizontala inferioara */
_wscroll = 0;
putch(cdj); /* Coltul dreapta jos */
_wscroll = 1; getch(); }
Programul 14.8.1
În ultima parte a programului s-a impus anularea temporară a scrierii pe ecran cu “scroll”
pentru ca la trasarea colţului din dreapt jos să se împiedice saltul la linie nouă. În caz
contrar, s-ar pierde linia superioară din cadru prin derularea conţinutului ferestrei în sus.
Dacă funcţia cadru se descrie prin intermediul structurii text_info, atunci
coordonatele colţurilor stînga sus şi dreapta jos ale unui cadru vor fi precizate prin
window în modulul principal. În desenarea chenarului coordonatele sînt relative la
fereastra curentă, nu la întreg ecranul.
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
void cadru(int);
void main()
{ clrscr();
window(1, 2, 80, 5); cadru(12);
window(1, 6, 80, 22); cadru(14);
window(64, 8, 78, 10); cadru(11);
window(67, 19, 78, 21); cadru(11);
getch(); }
void cadru(int culoare)
{ unsigned char css=218, co=196, cds=191, cv=179, csj=192, cdj=217;
int i, dx, dy;
struct text_info dw;
textcolor(culoare);
gettextinfo(&dw); /*Determina dimensiunile unei ferestre */
dx = dw.winright – dw.winleft + 1; /* Latimea ferestrei */
dy = dw.winbottom – dw.wintop + 1; /* Inaltimea ferestrei */
gotoxy(1, 1); putch(css); /* Coltul stinga sus */
for( i = 2; i<=dx; ++i) putch(co); /* Linie orizontala superioara */
putch(cds); /* Coltul dreapta sus */
8
for( i = 2; i<=dy; ++i)
{ gotoxy(1, i); putch(cv); /* Linie verticala stinga */
gotoxy(dx, i); putch(cv); /* Linie verticala dreapta */
}
gotoxy(1, dy); putch(csj); /* Coltul stinga jos */
for( i = 2; i<=dx; ++i) putch(co); /* Linie orizontala inferioara */
_wscroll=0;
putch(cdj); /* Coltul dreapta jos */
_wscroll=1; getch(); }
Programul 14.8.2
Logica de rezolvare a problemei şi comentariul făcut la sfîrşitul programului
anterior privitor la anularea temporară a scrierii pe ecran cu “scroll” rămîn neschimbate,
doar mecanismul de codificare este altul.
Observaţie. În mod analog, în modul grafic există funcţii predefinite specifice de
desenare figuri geometrice, stiluri de linii şi modele de haşurare. De exemplu,
pentru figurile geometrice uzuale se menţionează cîteva:
void far line(int x, int y, int x1, int y1);,
void far linerel(int dx, int dy); şi
void far lineto(int x, int y);. Funcţia line() are ca efect trasarea unei linii între
punctele de coordonate (x, y) şi (x1, y1), fără modificarea poziţiei curente. Pentru funcţia
linerel(), punctul iniţial este poziţia curentă a cursorului, iar coordonatele punctului final
se obţine incrementînd cu dx şi dy abscisa şi respectiv ordonata poziţiei curente. Punctul
final devine noua poziţie curentă. Ultima funcţie desenează o linie între poziţia curentă şi
punctul de coordonate (x, y), care stabileşte noua poziţie curentă.
Apelul funcţiei void far rectangle(int x, int y, int x1, int y1); permite
desenarea unui dreptunghi, unde colţul din stînga sus este punctul de coordonate (x, y),
iar colţul din dreapta jos este (x1, y1).
Cu funcţia void far circle(int x, int y, int r); se desenează un cerc cu centrul în
(x, y) şi de rază r.
Pentru desenarea unui arc de cerc pe lîngă centrul cercului şi rază trebuie să se
specifice, în grade, unghiurile de început şi de sfîrşit ale arcului:
void far arc(int x, int y, int unghi_start, int unghi_final, int r);. Dacă
unghi_start este 0˚ şi unghi_final este 360˚, atunci se trasează un cerc complet.
Un arc de elipsă poate fi efectul activării funcţiei:
void far ellipse(int x, int y, int unghi_start, int unghi_final, int axa_o, int axa_v);.
9
1. Încapsularea. Spre deosebire de programarea procedurală, unde structurile de date se
tratează separat de către algoritmi cu nivele diferite de complexitate, prin încapsularea
datelor se încearcă, pe de o parte tratarea mai apropiată de realitate a structurilor de date,
în sensul că se precizează, strict, numai modurile în care se poate opera asupra acestora,
iar pe de alta protejarea structurilor de date împotriva unor accidente nedorite, ca de
exemplu suprascrierea din greşeală.
2. Moştenirea tranzitivă. Tratarea adecvată a realităţii complexe şi diverse, în continuă
transformare şi modificare, presupune traducerea în practica programării a noţiunilor de
gen proxim şi diferenţă specifică. Definirea obiectului de bază cuprinde aspectele
esenţiale (aspectele ce redau genul proxim) în descrierea şi manipularea obiectului.
Adăugînd succesiv alte caracteristici specifice la descrierea obiectului definit anterior se
obţine un nou obiect. În acest mod se poate construi o structură arborescentă de clase, de
tip descendent înlănţuit. Obiectele din clasele descendente preiau automat atît datele
(însuşirile, caracteristicile) cît şi metodele (capacităţile) din obiectele strămoş (definitor)
pe linie ascendentă pînă la rădăcina arborelui. Cu alte cuvinte, transmiterea ereditară a
caracteristicilor şi capacităţilor unui obiect într-o ierahie de obiecte este un proces
tranzitiv, şi anume: dacă obiectul O2 este urmaşul obiectului O1, iar obiectul O3 este
urmaşul obiectului O2, atunci O3 este urmaşul lui O1.
Numărul de descendenţi este nedeterminat şi moştenirea se măreşte proporţional cu
lungimea adîncimii unei ramuri. Ordinea de amplasare a textelor care definesc tipurile de
clasă trebuie să cuprindă mai întîi tipurile de clasă care vor servi ca strămoş, descendenţii
urmează după aceea. Definiţiile metodelor pot fi aşezate oriunde, compilatorul le culege
în ordinea corectă.
3. Polimorfismul. Structura metodelor care acţionează asupra obiectelor poate fi
reconfigurată ulterior în cadrul ierarhiei de obiecte stabilită conform cerinţelor
utilizatorului. Deci, un indentificator de recunoaştere al unei metode moştenite poate fi
redefinit în cadrul ierarhiei de obiecte. Redefinirea unei metode moştenite are ca efect
crearea unei noi metode cu un bloc de metodă diferit şi dacă este cazul cu o altă listă de
parametri. Astfel, diferite variante ale unei metode pot acţiona automat şi în mod specific
asupra obiectelor de pe diverse nivele de ierarhizare, aşa cum se întîmplă, de exemplu, în
cazul metodelor virtuale.
10
tipuri aritmetice sau pot fi şiruri de caractere. Valorile lor sînt citite în ordine, iar orice
caracter invalid provoacă întreruperea operaţiei de citire.
Pentru scrierea a n valori pe ecranul calculatorului se utilizează operatorul cout cu
următoarea sintaxă generală:
cout<< nume_var_1<< nume_var_2<< …<<nume_var_n;.
Variabilile nume_var_i, cu i = 1,2, …, n, pot fi cu tipuri aritmetice, şiruri de caractere
sau pointeri. La pointeri nu se admite tipul char.
Un exemplu de utilizare a operatorilor cin şi cout se prezintă în programul de mai jos:
/* Operatorii cin si cout */
#include <iostream.h>
void main (void)
{ int i;
float j;
cout << “Intrduceti i si j: ”;
cin >>i>>j;
cout<<”\nS-au citit valorile ”<< i<<” si ”<<j<<’\n’; }
Introduceti i si j: 15 22.45
S-au citit valorile 15 si 22.45
Programul 14.9.1
Alte informaţii despre POO necesită un timp îndelungat. Spre informare se recomandă
consultarea bibliogafiei, prezentată în primul curs.
11