11.3. Các thủ tục đồ họa cơ bản
11.3.5 Vẽ một hình chữ nhật
Hàm rectangle ( ) vẽ một hình chữ nhật bằng cách sử dụng màu đang dùng.
Khuôn mẫu chuẩn dùng cho hàm rectangle ( ) được viết như sau:
void rectangle (int x1, int y1, int x2, int y2);
Chương trình 11-4 hiển thị một điện trở riêng lẻ trên màn hình. Hàm draw_resistor (x,y) vẽ điện trở này tại điểm bắt đầu có tọa độ (x,y). Một vấn đề xuất hiện khi tiến hành hiển thị đồ họa là việc hiển thị đồ họa có thể làm thay đổi số lượng các điểm ảnh có thể hiển thị. Nếu sử dụng tọa độ tuyệt đối thì khi màn hình có độ phân giải cao đối tượng sẽ xuất hiện tương đối nhỏ, còn khi màn hình có độ phân giải thấp đối tượng lại trở lên lớn hơn. Vì thế trong chương trình này, điện trở được vẽ theo tỉ lệ
đối với các tọa độ cực đại x- và y-; biện pháp này làm cho các tọa độ của nó được tính tương đối so với kích thước của màn hình.
#include <stdio.h>
#include <graphics.h>
enum errors {NO_ERROR=0,GRAPHICS_ERROR};
int open_graphics(void);
void draw_resistor(int x,int y);
int main(void) {
if (open_graphics()==GRAPHICS_ERROR) return(GRAPHICS_ERROR);
draw_resistor(100,200);
getchar();
closegraph();
return(NO_ERROR);
}
int open_graphics(void) {
int gdriver=DETECT,gmode,errorcode;
initgraph(&gdriver,&gmode,"");
errorcode=graphresult();
if (errorcode != grOk) {
printf("Graphics error: %s\n",grapherrormsg(errorcode));
return(GRAPHICS_ERROR);
}
return(NO_ERROR);
}
void draw_resistor(int x,int y) {
int maxx,maxy;
struct {
int length, width, connectline;
} res;
maxx=getmaxx();
maxy=getmaxy();
res.length=maxy/20;
res.width=maxx/40;
res.connectline=maxy/20;
line(x,y,x,y+res.length);
rectangle(x-res.width/2,y+res.connectline,
x+res.width/2, y+res.connectline+res.length);
line(x,y+res.connectline+res.length,
x,y+res.length+2*res.connectline);
}
6 Hiển thị văn bản
Hàm ourtextxy ( ) gửi một xâu tới thiết bị lối ra. Các giá trị số không thể được hiển thị trực tiếp trên màn hình mà cần được chuyển đổi thành một xâu trước khi chúng được hiển thị. Khuôn mẫu chuẩn dùng cho hàm ourtextxy ( ) như sau:
void outtextxy (int x, int y, char *textstring);
Chương trình 11-5 sử dụng hàm outtextxy ( ) để hiển thị một xâu giá trị điện trở bên trong hàm draw _resistor ( ).
Chương trình 11-5:
#include <stdio.h>
#include <graphics.h>
enum errors {NO_ERROR=0,GRAPHICS_ERROR};
int open_graphics(void);
void draw_resistor(int x,int y, char str[]);
int main(void) {
if (open_graphics()==GRAPHICS_ERROR) return(GRAPHICS_ERROR);
draw_resistor(100,200,"100 K");
draw_resistor(200,200,"200 K");
getchar();
closegraph();
return(NO_ERROR);
}
int open_graphics(void) {
int gdriver=DETECT,gmode,errorcode;
initgraph(&gdriver,&gmode,"");
errorcode=graphresult();
if (errorcode != grOk) {
printf("Graphics error: %s\n",grapherrormsg(errorcode));
return(GRAPHICS_ERROR);
}
return(NO_ERROR);
}
7 Vẽ một vòng tròn
Hàm circle( ) thực hiện công việc vẽ một vòng tròn với một bán kính cho trước và có tâm tại điểm (x,y). Khuôn mẫu chuẩn cho hàm circle ( ) như sau:
void circle (int x, int y, int radius);
Chương trình 11-6 dùng hàm circle ( ) để hiển thị một điện áp nguồn.
#include <stdio.h>
#include <graphics.h>
enum errors {NO_ERROR=0,GRAPHICS_ERROR};
int open_graphics(void);
void draw_resistor(int x,int y, char str[]);
void draw_voltage_source(int x,int y, char str[]);
int main(void) {
if (open_graphics()==GRAPHICS_ERROR) return(GRAPHICS_ERROR);
draw_resistor(200,200,"100 K");
draw_resistor(300,200,"200 K");
draw_voltage_source(100,200,"5 V");
getchar();
closegraph();
return(NO_ERROR);
}
int open_graphics(void) {
int gdriver=DETECT,gmode,errorcode;
initgraph(&gdriver,&gmode,"");
errorcode=graphresult();
if (errorcode != grOk) {
printf("Graphics error: %s\n",grapherrormsg(errorcode));
return(GRAPHICS_ERROR);
}
return(NO_ERROR);
}
void draw_resistor(int x,int y, char str[]) {
int maxx,maxy;
struct {
int length, width, connectline;
} res;
maxx=getmaxx();
maxy=getmaxy();
res.length=maxy/20;
res.width=maxx/40;
res.connectline=maxy/20;
line(x,y,x,y+res.length);
rectangle(x-res.width/2,y+res.connectline,
x+res.width/2, y+res.connectline+res.length);
line(x,y+res.connectline+res.length,
x,y+res.length+2*res.connectline);
outtextxy(x+res.width,y+res.length/2+res.connectline,str);
}
void draw_voltage_source(int x,int y, char str[]) {
int maxy;
struct {
int radius, connectline;
} volt;
maxy=getmaxy();
volt.radius=maxy/40;
volt.connectline=maxy/20;
line(x,y,x,y+volt.connectline);
circle(x,y+volt.connectline+volt.radius,volt.radius);
line(x,y+volt.connectline+2*volt.radius, x,y+2*volt.radius+2*volt.connectline);
outtextxy(x+volt.connectline+volt.radius, y+volt.radius+volt.connectline,str);
}
8 Vẽ ảnh bitmap
Chương trình 11-7 sẽ hiển thị một khuôn mặt có thể di chuyển được xung quanh màn ảnh bằng cách sử dụng các phím mũi tên trên bàn phím. Hình 11-5 chỉ ra một hình hiển thị làm mẫu.
Hàm getch( ) được sử dụng để phát hiện khi có một phím trên bàn phím bị nhấn. Nếu hàm này trả lại giá trị là 0 thì phím được nhấn là một ký tự mở rộng, chẳng hạn một phím chức năng ( F1…F12), các phím sang trang Page up, Page down, các phím mũi tên,…v.v. Các ký tự mở rộng có thể được xác định bằng cách gọi hàm getch( ) trở lại.
Các giá trị trả lại làm mẫu được liên kết trong bảng 11-4 Các giá trị trả lại
Mũi tên hướng lên Mũi tên hướng xuống Mũi tên hướng sang trái Mũi tên hướng sang phải Phím thoát (ESC)
Phím 72 80 75 77 27
Dòng mã dưới đây xác định xem liệu một phím chức năng vừa được nhấn:
ch= getch ( ); if ( ch = = 0) ch = getch( );
Thí dụ, nếu nhấn phím Esc thì biến ch sẽ lưu giá trị 27.
Chương trình 11-7:
/*****************************************************/
/* FACE.C */
/* Tiêu đề: Chuong trinh di chuyen nen */
/* Chức năng: Chuong trinh hien thi mot vung nen */
/* Co the su dung phim mui ten de di chuyen */
/****************************************************/
#include <conio.h>
#include <graphics.h>
#include <alloc.h>
#include <stdio.h>
#include <process.h> /* required for exit() */
#define UPARROW 72
#define DOWNARROW 80
#define LEFTARROW 75
#define RIGHTARROW 77
#define ESC 27
#define INCREMENT 4
enum errors {NO_ERROR=0,GRAPHICS_ERROR,GRAPHICS_MEM_ERROR};
int open_graphics(void);
void *get_shape(void);
int main(void) {
void *shape;
int x,y,ch;
if (open_graphics()==GRAPHICS_ERROR) return(GRAPHICS_ERROR);
shape=get_shape();
if (shape==NULL) {
puts("Cannot allocate enough graphics memory");
return(GRAPHICS_MEM_ERROR);
}
x=getmaxx()/2; y=getmaxy()/2;
do {
putimage(x, y, shape, XOR_PUT);
/* Vẽ ảnh */
ch=getch(); if (ch==0) ch=getch(); /* Đọc vào 1 phím */
putimage(x, y, shape, XOR_PUT); /* xóa ảnh */
if (ch==UPARROW) y-=INCREMENT;
else if (ch==DOWNARROW) y+=INCREMENT;
else if (ch==LEFTARROW) x-=INCREMENT;
else if (ch==RIGHTARROW) x+=INCREMENT;
if (x>0.9*getmaxx())x=0.9*getmaxx();
if (x<0) x=0;
if (y>0.9*getmaxy())y=0.9*getmaxy();
if (y<0) y=0;
} while (ch!=ESC);
closegraph();
return(NO_ERROR);
}
int open_graphics(void) {
int gdriver=DETECT,gmode,errorcode;
initgraph(&gdriver,&gmode,"");
errorcode=graphresult();
if (errorcode != grOk) {
printf("Graphics error: %s\n",grapherrormsg(errorcode));
return(GRAPHICS_ERROR);
}
return(NO_ERROR);
}
void *get_shape(void) {
int startx,starty ; void *al;
int ulx, uly, lrx, lry, size, buffsize;
/* Draw shape */
setfillstyle( SOLID_FILL,WHITE );
startx=getmaxx()/2; starty=getmaxy()/2;
size=getmaxx()/20;
/* draw face outline */
circle(startx,starty,size);
floodfill(startx,starty,WHITE);
/* Vẽ mắt */
setcolor(RED);
circle(startx+size/3,starty,size/3);
floodfill(startx+size/3,starty,WHITE);
circle(startx-size/3,starty,size/3);
floodfill(startx+size/3,starty,WHITE);
/* get size of face */
ulx = startx-size;
uly = starty-size;
lrx = startx+size;
lry = starty+size;
buffsize = imagesize(ulx, uly, lrx, lry);
al = malloc( buffsize );
getimage(ulx, uly, lrx, lry, al);
putimage(ulx, uly, al, XOR_PUT);
return(al);
}
Hàm getimage (x1,y1,x2,y2) thu thập hình ảnh từ các tọa độ (x1, y1) tới (x2, y2) vào trong bộ nhớ và hàm putimage (x, y, BITMASK) được sử dụng để hiển thị hình ảnh và xóa ảnh đó khỏi màn hình. Cách nhanh nhất để xóa bỏ một đối tượng ảnh là thực hiện phép loại trừ XOR tất cả các bit của đối tượng ảnh với chính nó. Hàm putimage (x, y, BITMASK) cho phép một mặt nạ bit được áp dụng cho hình ảnh. Hàm OR- loại trừ được định nghĩa với XOR_PUT. Chẳng hạn, nếu các bit trên một đoạn của màn hình là 11001010, thì khi thực hiện OR-loại trừ với chính nó kết quả sẽ là 00000000.