ĐỒ HỌA PASCAL
I. MÀN HÌNH TRONG CHẾ ĐỘ ĐỒ HỌA ( GRAPHIC)
Hình ảnh trong chế độ đồ họa được tạo ra bằng các điểm ảnh (Pixel), số điểm ảnh của màn hình đồ họa tùy thuộc vào từng loại CARD màn hình và MODE qui định cho màn hình đó.
Việc lập trình trong chế độ đồ họa cần phải xác định được loại màn hình đang sử dụng và chương trình phải vận hành được trên nhiều loại màn hình khác nhau.
Tọa độ của một điểm ảnh trên màn hình đồ họa cũng giống như trong chế độ văn bản (TEXT) với điểm ảnh đầu tiên trên góc trái màn hình là (0,0), tọa độ đỉnh dưới phải tùy thuộc vào độ phân giải của màn hình, CARD màn hình và MODE màn hình.
Để dử dụng được chế độ đồ họa trên màn hình, ta cần phải có các File sau:
GRAPH.TPU Chứa các lệnh đồ họa
* .BGI Chứa Font màn hình
* .CHR Chứa Font ký tư
II. KHỞI TẠO VÀ THOÁT KHỎI CHẾ ĐỘ ĐỒ HỌA
2.1. Khởi tạo chế độ đồ họa
Thủ tục INITGRAPH(Gd,Gm:Integer; Path:String);
trong đó:
- Gd: Chỉ CARD màn hình.
Thông thường, một chương trình phải được chạy trên nhiều loại màn hình khác nhau nên ta có thể khai báo:
Gd = Detect ( = 0 )
Với hằng Detect, máy sẽ tự động tìm CARD màn hình tương ứng để chạy chương trình.
- Gm: Chỉ MODE màn hình.
Trong trường hợp khai báo Gd = Detect thì không cần thiết phải khai báo Gm vì máy tính sẽ tự xác định loại CARD màn hình và thiết lập chế độ MODE màn hình tương ứng với CARD màn hình đó.
- Path: Đường dẫn đến nơi chứa các file *.BGI. Nếu Path = ‘’ thì ta hiểu là các file *.BGI nằm trong thư mục hiện hành.
Hàm GRAPHRESULT:Integer;
Hàm này trả về kết quả của việc khởi động đồ họa.
= 0 : Thành công.
<>0 : Bị lỗi.
Tên của lỗi được xác định bởi hàm GRAPHERRORMSG(Er:Integer):String;
Hàm này cho ra một xâu ký tự thông báo lỗi của đồ họa xác định bởi đối số Er.
* Hằng số GrOK = 0: Việc khởi động đồ họa có lỗi.
Ví dụ:
Uses Graph; Procedure ThietLapDoHoa; var gd,gm,Gr:integer; Begin DetectGraph(Gd,Gm); InitGraph(gd,gm,'C:\TP\BGI'); Gr:=GraphResult; If Gr<>GrOK then Begin writeln('Loi Do hoa: ',GraphErrorMsg(Gr)); Halt(1); End; End; BEGIN ThietLapDoHoa; . . . END.
Chú ý: Ta có thể khởi tạo mode đồ hoạ với chế độ 256 màu bằng cách sử dụng hàm InstallUserDriver(Name:String;Ptr:Pointer):Integer; với điều kiện trên đĩa phải có file SVGA256.BGI.
Procedure ThietLapDoHoa; var gd,gm,Gr:integer; Begin Gd:= InstallUserDriver(SVGA256,NIL); Gm:=2; {Mode 640x480x256} InitGraph(gd,gm,'C:\TP\BGI'); End;
2.2. Thoát khỏi chế độ đồ họa
Thủ tục CLOSEGRAPH;
Sau đây là cấu trúc chung của một chương trình đồ họa:.
Uses Crt,Graph; Procedure ThietLapDoHoa; var gd,gm,Gr:integer; Begin DetectGraph(Gd,Gm); InitGraph(gd,gm,'C:\TP\BGI'); Gr:=GraphResult; If Gr<>GrOK then Begin writeln('Loi Do hoa: ',GraphErrorMsg(Gr)); Halt(1); End; End; BEGIN ThietLapDoHoa; . . . CloseGraph; END.
III. TỌA ĐỘ VÀ CON TRỎ TRÊN MÀN HÌNH ĐỒ HỌA
3.1. Hàm GetMaxX:Integer;
Cho tọa độ cột lớn nhất của màn hình.
3.2. Hàm GetMaxY:Integer;
Cho tọa độ dòng lớn nhất của màn hình.
3.3. Thủ tục MOVETO(x,y:Integer);
Di chuyển con trỏ từ vị trí đang đứng đến tọa độ (x,y).
3.4. Thủ tục MOVEREL(dx,dy:Integer);
Di chuyển con trỏ từ vị trí đang đứng đến tọa độ mới cách tọa độ cũ khoảng cách là dx, dy.
3.5. Vẽ một điểm trên màn hình:
Dùng thủ tục PUTPIXEL(x,y:Integer; color:Word);
3.6. Lấy màu của một điểm tại tọa độ x,y:
Hàm GETPIXEL(x,y:Integer):Word;
IV. ĐẶT MÀU TRÊN MÀN HÌNH ĐỒ HỌA
4.1. Đặt màu cho đối tượng cần vẽ
Dùng thủ tục SETCOLOR(Color:Byte);
4.2. Đặt màu nền
Dùng thủ tục SETBKCOLOR(Color:Byte);
V. CỬA SỔ TRONG CHẾ ĐỘ ĐỒ HỌA
5.1. Đặt cửa sổ trên màn hình
Thủ tục SETVIEWPORT(x1,y1,x2,y2:Integer; Clip:Boolean);
Với x1,y1: đỉnh trên trái của cửa sổ.
x2,y2: đỉnh dưới phải của cửa sổ.
Clip = TRUE: những gì vượt khỏi màn hình sẽ bị cắt bỏ.
Clip = FALSE: những gì vượt khỏi màn hình sẽ không bị cắt bỏ.
* Khi tạo cửa sổ thì tọa độ trên màn hình sẽ thay đổi theo.
Tọa độ mới = Tọa độ cũ – Tọa độ đỉnh trên trái.
5.2. Xóa hình ảnh trong cửa sổ
- Xóa hình ảnh trong cửa sổ, ta dùng thủ tục CLEARVIEWPORT;
- Xóa toàn bộ màn hình, ta dùng thủ tục CLEARDEVICE;
VI. VIẾT CHỮ TRONG CHẾ ĐỘ ĐỒ HỌA
6.1. Chọn Font chữ
Ta dùng thủ tục SETTEXTSTYLE(font,Dir,size:Word);
- Các font có thể chứa các hằng sau:
DefaultFont = 0; TriplexFont = 1; SmallFont = 2;
SansSerifFont = 3; GothicFont = 4;
- Dir có các hằng sau:
HorizDir = 0 Từ trái qua phải.
VetDir = 1 Từ dưới lên trên.
- Size: độ lớn của chữ.
6.2. Chọn phân bố chữ
Dùng thủ tục SETTEXTJUSTIFY(Hz,Vt:Word);
Chọn vị trí của chữ xung quanh tọa độ định sẵn.
- Hz là phân bố chữ theo trục ngang. Có các hằng sau:
LeftText = 0 Chữ viết nằm bên phải trục đứng.
CenterText = 1 Chữ viết nằm ở giữa trục đứng.
RightText = 2 Chữ viết nằm bên trái trục đứng.
- Vt là bố trí chữ theo hướng dọc đối với tọa độ qui định xuất chuỗi. Các hằng liên quan:
BottomText = 0 Chữ viết nằm bên trên trục ngang.
CenterText = 1 Chữ viết nằm ở giữa trục ngang.
TopText = 2 Chữ viết nằm bên dưới trục ngang.
6.3. Viết một xâu ký tự lên màn hình
- Xuất một xâu ký tự tại vị trí con trỏ:
Dùng thủ tục OUTTEXT(St:String);
- Xuất một xâu ký tự tại tọa độ x,y:
Dùng thủ tục OUTTEXTXY(x,y:Word; St:String);
Chú ý: Cách xuất chuỗi của hai thủ tục trên được qui định trong thủ tục SETTEXTJUSTIFY và SETTEXTSTYLE.
VII. VẼ CÁC HÌNH CƠ BẢN
7.1. Chọn kiểu đường
Dùng thủ tục SETLINESTYLE(Ls,Pt,Tk:Word);
Thủ tục này xác định kiểu đường được vẽ trong đồ họa.
Ls: kiểu đường vẽ. Ls có các giá trị sau:
0: Đường liền nét
1: Nét đứt
2: Nét chấm gạch
3: Nét gạch
4: Đường do người thiết kế tạo ra.
Pt: xác định màu vẽ.
. Nếu Ls = 0..3 thì Pt=0 (Lấy giá trị Default)
. Nếu Ls = 4 thì Pt là số nguyên chỉ màu của kiểu đường.
Tk: xác định độ dày của đường.
Tk = 1: bình thường.
Tk = 3: đậm nét.
7.2. Vẽ đoạn thẳng
LINE(x1,y1,x2,y2:Integer); vẽ từ điểm (x1,y1) đến điểm (x2,y2)
LINETO(x,y:Integer); vẽ từ vị trí con trỏ đến điểm (x,y)
LINEREL(dx,dy:Integer); vẽ từ vị trí con trỏ đến điểm cách đó một khoảng dx,dy.
7.3. Vẽ hình chữ nhật
Dùng thủ tục RECTANGLE(x1,y1,x2,y2:Integer);
7.4. Vẽ cung tròn
Thủ tục ARC(x,y:Integer; g1,g2,R:Word);
Vẽ cung tròn có tâm (x,y) bán kính R, góc bắt đầu là g1 và góc kết thúc là g2.
7.5. Vẽ đường tròn – Ellip
Thủ tục vẽ đường tròn: CIRCLE(x,y:Integer; R:Word);
Thủ tục ELLIPSE(x,y:integer; g1,g2,Rx,Ry:Word);
Vẽ Ellip có tâm (x,y) bán kính ngang Rx, bán kính dọc Ry, góc bắt đầu là g1 và góc kết thúc là g2.
7.6. Định MODE đường vẽ
Thủ tục SETWRITEMODE(Mode:Integer);
- Định Mode vẽ cho các đường thẳng.
- Ta có thể chọn Mode bằng các hằng:
CopyPut = 0; XORPut = 1;
Trong đó:
. CopyPut là Mode chèn, đường mới sẽ không xóa đường cũ.
. XORPut là Mode xóa, đường mới sẽ xóa đường cũ.
XIII. TÔ MÀU CÁC HÌNH
8.1. Chọn kiểu tô
Thủ tục SETFILLSTYLE(Pt,Cl:Word);
Với:
- Pt: Mẫu tô của hình. Có các hằng từ 0 đến 12.
0: Tô bằng màu nền.
1: Tô bằng màu viền.
2: Tô bằng các dấu —
……………………………..
- Cl: Màu tô của hình.
8.2. Vẽ hình chữ nhật có tô màu ở bên trong
Thủ tục BAR(x1,y1,x2,y2:Integer);
Vẽ hình chữ nhật có tô màu và mẫu tô được xác định bởi thủ tục SETFILLSTYLE.
8.3. Vẽ hình hộp chữ nhật
Thủ tục BAR3D(x1,y1,x2,y2,Dh:Word; Top:Boolean);
Vẽ hình hộp chữ nhật có tọa độ đỉnh trên là (x1,y1), đỉnh dưới là (x2,y2) và chiều dày là Dh.
Top = TRUE: Hình hộp có nắp.
Top = FALSE: Hình hộp không có nắp.
8.4.Vẽ hình Ellip
Thủ tục FILLELLIPSE(x,y:Integer; Rx,Ry:Word);
8.5. Vẽ hình quạt tròn
Thủ tục PIESLICE(x,y:Integer; g1,g2,R:Word);
Vẽ hình quạt tròn có tâm (x,y), góc đầu g1, góc cuối g2, bán kính R.
8.6. Vẽ hình quạt Ellip
thủ tục SECTOR(x,y:Integer; g1,g2,Rx,Ry:Word);
8.7. Làm loang màu một vùng kín
Thủ tục FLOODFILL(x,y:Integer; Color:Word);
Trong đó:
(x,y): điểm nằm trong vùng kín.
Color: màu muốn tô.
8.8. Vẽ đa giác
Đối với một đa giác bất kỳ có N đỉnh, ta phải khai báo N+1 đỉnh để vẽ đường gấp khúc với tọa độ điểm đầu trùng với tọa độ điểm cuối.
Để vẽ đa giác ta dùng thủ tục: DRAWPOLY(Np:Word; Var P);
trong đó:
- Np: số đỉnh của đa giác + 1
- P: chứa tọa độ các đỉnh, là một mảng có Np thành phần có kiểu dữ liệu là PointType được định nghĩa trong Unit Graph như sau:
TYPE PointType = Record
x,y: Integer;
End;
IX. CÁC KỸ THUẬT TẠO HÌNH CHUYỂN ĐỘNG
9.1. Kỹ thuật lật trang màn hình
CARD màn hình có nhiều trang, mỗi trang được đánh số 0,1,2,…
Để vẽ hình lên một trang màn hình, ta dùng thủ tục:
SETACTIVEPAGE(Page:Word);
Trong đó, Page là số của trang màn hình. Thủ tục này được đặt trước khi có lệnh vẽ lên màn hình.
Để đưa trang màn hình ra màn hình, ta dùng thủ tục:
SETVISUALPAGE(Page:Word);
Page: trang màn hình muốn xem.
Thông thường, màn hình sẽ làm việc và hiện ra trên trang 0. Do đó, để vừa xem màn hình vừa vẽ lên trang màn hình khác, ta thường dùng hai thủ tục trên đi kèm với nhau.
Để thực hiện tự động chương trình khi sử dụng cú pháp lật hình này, ta thường theo một giải thuật sau:
- Tạo biến page1,page2:Word;
- Tạo vòng lặp
…
Repeat
SetVisualPage(page1); (* Xem trang màn hình page1 *)
SetActivePage(page2); (* Vẽ hình lên trang page2 *)
…….
< Các thủ tục vẽ hình >
…….
(* Hoán vị 2 biến page1, page2 *)
Temp:=page1;
page1:=page2;
page2:=Temp;
Until <Điều kiện thoát>;
9.2. Lưu và di chuyển một vùng màn hình
Chúng ta có thể lưu một vùng màn hình vào bộ nhớ rồi sau đó lại dán nó lên màn hình tại một vị trí khác.
Lưu một vùng màn hình vào bộ nhớ được thực hiện bằng thủ tục:
GETIMAGE(x1,y1,x2,y2:Integer; Var P:Pointer);
trong đó P là con trỏ để lưu nội dung của vùng (x1,y1,x2,y2).
Việc đăng ký một vùng nhớ động phải được khai báo dung lượng cần thiết. Dung lượng vùng nhớ được thực hiện bằng hàm:
IMAGESIZE(x1,y1,x2,y2:Integer):Word;
Để hiện hình ảnh từ bộ nhớ ra màn hình, ta dùng thủ tục:
PUTIMAGE(x,y:Integer; P:Pointer; Mode:Word);
trong đó:
(x,y): Tọa độ đỉnh trái hình chữ nhật mà ta muốn đưa ra.
P : Con trỏ lưu vùng hình chữ nhật.
Mode: Hằng số chỉ phương thức hiện ra màn hình. Mode chứa một trong các hằng sau:
NormalPut = 0: Xuất ra như đã lưu (phép MOV)
XORPut = 1: Phép XOR, xóa hình cũ nếu hai hình giao nhau.
ORPut = 2: Phép OR, lấy cả hai hình nếu hai hình giao nhau.
ANDPut = 3: Phép AND, nếu hai hình giao nhau thì lấy phần chung.
NOTPut = 4: Phép NOT, cho ra âm bản.
Về việc thực hiện ta tiến hành như sau:
- Khai báo một biến con trỏ P:Pointer;
- Đăng ký một vùng nhớ động do P qủan lý bằng thủ tục
GETMEM(P,ImageSize(x1,y1,x2,y2));
- Lưu hình ảnh bằng thủ tục GETIMAGE(x1,y1,x2,y2,P^);
- Xuất ra màn hình bằng thủ tục PUTIMAGE(x,y,P^,Mode);
BÀI TẬP MẪU
Bài tập 10.1: Viết dòng chữ có bóng trong chế độ 256 màu.
Uses crt,Graph; var gd,gm:integer; Procedure WriteStr(dx,dy:Integer;st:String); Var i,j:Integer; Begin settextstyle(5,0,8); j:=16; (* Viet chu bong *) for i:=0 to 15 do begin setcolor(j); outtextxy(dx+i,dy+i,st); inc(j); end; setcolor(40); outtextxy(dx+i,dy+i,st); End; Begin gd:=INSTALLUSERDRIVER('SVGA256',NIL); GM:=4; initgraph(gd,gm,'c:\bp\BGI'); WriteStr(1,100,' Pham Anh Phuong'); readln; CloseGraph; End.
Bài tập 10.2: Vẽ các hình chữ nhật ngẫu nhiên trên màn hình.
Uses Crt,Graph;
Procedure ThietLapDohoa;
Var Gd,Gm:Integer;
Begin
Gd:=0;
InitGraph(Gd,Gm,’D:\BP\BGI’);
End;
Function RandColor:Byte;
Begin
RandColor:=Random(MaxColors – 1)+1;
End;
Procedure DeMo;
Var x1,y1,x2,y2:Integer;
Begin
Randomize;
Repeat
x1:=Random(GetMaxX);
y1:=Random(GetMaxY);
x2:=Random(GetMaxX – x1) + x1;
y2:=Random(GetMaxX – y1) + y1;
SetColor(RandColor);
Rectangle(x1,y1,x2,y2);
Delay(500);
Until KeyPressed;
End;
BEGIN
ThietLapDohoa;
DeMo;
CloseGraph;
END.
Bài tập 10.3: Vẽ một kim đồng hồ quay quanh tâm O(x0,y0).
Uses crt,Graph; Var x0,y0:word; Alpha,Beta,R:real; Procedure VeDgt(x0,y0:word; R,Alpha:real); Begin Line(x0,y0,x0+Round(R*Cos(Pi*Alpha/180)), y0-Round(R*Sin(Pi*Alpha/180))); End; BEGIN ThietLapDoHoa; x0:=GetMaxX div 2; y0:=GetMaxY div 2; R:=100; Alpha:=90; Beta:=6; SetWriteMode(XORPut); VeDgt(x0,y0,R,Alpha); Repeat VeDgt(x0,y0,R,Alpha); Alpha:=Alpha - Beta; VeDgt(x0,y0,R,Alpha); Delay(250); Until KeyPressed; CloseGraph; END.
Bài tập 10.4: Viết chương trình tạo Menu cho phép chọn và thực hiện các chức năng bằng cách di chuyển mũi tên trên các hộp sáng, các thủ tục thực hiện xong quay trỏ lại Menu chính. Nhấn ESC để thoát khỏi chương trình.
USES crt,graph; Const mau1 =15; mau2 =8; maumn=7; XTop=200; YTop=100; Dy=32; Dx=250; Type MANG_MENU=Array[1..20] of string;{dung luu cac dong menu } MANG_THUTUC=Array[1..20] of Procedure;{dung luu cac thu tuc} var DongMN:MANG_MENU; ThuTuc:MANG_THUTUC; SoDong:byte; Procedure Wait; Var ch:Char; BEGIN ch:=ReadKey; END; {$F+} Procedure Modun1; BEGIN Line(50,50,200,300); Wait; END; Procedure Modun2; BEGIN Circle(200,200,100); Wait; END; Procedure Modun3; Begin Ellipse(200,300,0,360,100,150); Wait; End; Procedure Modun4; BEGIN Rectangle(50,50,200,300); Wait; END; Procedure Modun5; BEGIN OutTextXY(50,50,’Chao mung cac ban den voi chuong trinh do hoa’); Wait; END; Procedure Modun6; BEGIN OutTextXY(50,50,’Day la Menu do hoa’); Wait; END; Procedure Thoat; BEGIN Halt; END; {$F-} Procedure ThietLapDoHoa; var gd,gm:integer; Begin Gd:=0; InitGraph(gd,gm,'C:\BP\BGI'); End; Procedure Box(x1,y1,x2,y2:integer; MauVienTren,MauVienduoi,MauNen:byte); {Ve nut menu} Var i:Byte; begin setfillstyle(1,MauNen); bar(x1,y1,x2,y2); setcolor(MauVienTren); For i:=0 to 1 do Begin moveto(x1-i,y2+i); lineto(x1-i,y1-i); lineto(x2+i,y1-i); End; setcolor(MauVienDuoi); For i:=0 to 1 do Begin moveto(x2+i,y1-i); lineto(x2+i,y2+i); lineto(x1-i,y2+i); End; end; Procedure Ve_menu(Xdau,Ydau,DeltaX,DeltaY:Word; chon,SoDong:Byte;DongMN:MANG_MENU); Var i:Byte; Begin for i:=1 to SoDong do begin if i=chon then Box(Xdau,Ydau+i*DeltaY+6,Xdau+DeltaX,YDau+i*DeltaY+DeltaY, mau2,mau1,maumn) Else Box(Xdau,Ydau+i*DeltaY+6,Xdau+DeltaX,YDau+i*DeltaY+DeltaY, mau1,mau2,maumn); OutTextxy(Xdau+20,Ydau+15+i*DeltaY,DongMN[i]); end; End; Procedure PullDown(x,y,DeltaX,DeltaY:Word;SoDong:Byte; DongMenu:MANG_MENU;ThuTuc:MANG_THUTUC); Var sott,LuuSott,Chon,i:Byte; OK:Boolean; Function Select(Xdau,Ydau,DeltaX,DeltaY:Word;SoDong:Byte):Byte; var ch:char; j:Byte; Begin While True do Begin If KeyPressed then Begin ch:=readkey; case ch of #13: Begin {ENTER} select:=Sott; Exit; End; #72:Begin LuuSott:=Sott; Sott:=Sott-1; if Sott<1 then Sott:=SoDong; Select:=Sott; Box(XTop,YTop+LuuSoTT*DeltaY+6, Xdau+DeltaX,Ydau+LuuSoTT*DeltaY+DeltaY, Mau1,Mau2,maumn); Outtextxy(Xdau+20,Ydau+15+LuuSoTT*DeltaY, DongMN[LuuSoTT]); Box(Xdau,Ydau+SoTT*DeltaY+6, Xdau+DeltaX,Ydau+SoTT*DeltaY+DeltaY, Mau2,Mau1,maumn); Outtextxy(Xdau+20,Ydau+15+SoTT*DeltaY, DongMN[SoTT]); End; #80: Begin LuuSott:=Sott; Sott:=Sott+1; if Sott>SoDong then Sott:=1; Select:=Sott; Box(Xdau,Ydau+LuuSoTT*DeltaY+6, Xdau+DeltaX,Ydau+LuuSoTT*DeltaY+DeltaY,Mau1,Mau2,maumn); Outtextxy(Xdau+20,Ydau+15+LuuSoTT*DeltaY, DongMN[LuuSoTT]); Box(Xdau,Ydau+SoTT*DeltaY+6, Xdau+DeltaX,Ydau+SoTT*DeltaY+DeltaY,Mau2,Mau1,maumn); Outtextxy(Xdau+20,Ydau+15+SoTT*DeltaY, DongMN[SoTT]); End; #27: {ESC} Begin OK:=False; Exit; End; end; { of case key } End; End; End; Begin {PullDown} Sott:=1; OK:=TRUE; Ve_menu(X,Y,DeltaX,DeltaY,Sott,SoDong,DongMenu); While OK do { lap khong dieu kien } Begin Chon:=select(x,y,DeltaX,DeltaY,SoDong); For i:=1 to SoDong do If (i=Chon)and OK Then Begin ClearDevice; ThuTuc[i]; ClearDevice; Ve_Menu(X,Y,DeltaX,DeltaY,Sott,SoDong,DongMenu); End; end;{ of While } End; BEGIN SoDong:=7; DongMN[1]:='VE DOAN THANG '; DongMN[2]:='VE DUONG TRON'; DongMN[3]:='VE ELLIPSE'; DongMN[4]:='VE HINH CHU NHAT'; DongMN[5]:='VIET LOI CHAO'; DongMN[6]:='VIET DONG QUANG CAO'; DongMN[7]:='THOAT KHOI CHUONG TRINH'; ThuTuc[1]:=Modun1; ThuTuc[2]:=Modun2; ThuTuc[3]:=Modun3; ThuTuc[4]:=Modun4; ThuTuc[5]:=Modun5; ThuTuc[6]:=Modun6; ThuTuc[7]:=Thoat; ThietLapDoHoa; SetBKcolor(LightBlue); PullDown(XTop,YTop,DX,DY,SoDong,DongMN,ThuTuc); CloseGraph; END.
Bài tập 10.5: Vẽ hai hình
Sau đó, viết chương trình thực hiện chuyển động của miệng cá.
Uses Crt,Graph; Type ProType=Procedure; Var Gd,Gm:integer; page1,page2:word; Hinh:Array[0..1] of ProType; Xc,Yc,r:Integer; i:Byte; {$F+} Procedure HinhCa1; Begin SetColor(15); PieSlice(Xc,Yc,30,330,R); {Ve bung ca} SetColor(0); Circle(Xc + R div 2,Yc - R div 2,4); {Mat ca} End; Procedure HinhCa2; Begin SetColor(15); PieSlice(Xc,Yc,15,345,R); {Ve bung ca} SetColor(0); Circle(Xc + R div 2 ,Yc - R div 2,4); {Mat ca} End; {$F-} Begin gd:=4; InitGraph(gd,gm,’’); Xc:=GetMaxX div 2; Yc:=GetMaxY div 2; R:=50; i:=0; Hinh[0]:=HinhCa1; Hinh[1]:=HinhCa2; page1:=0; page2:=1; Repeat SetVisualPage(page1); SetActivePage(page2); i:=1-i; Hinh[i]; Delay(200); page1:=1-page1; page2:=1-page2; Until KeyPressed; CloseGraph; End.
Bài tập 10.6: Viết chương trình tạo một dòng chữ chạy ngang qua màn hình.
Uses crt,graph; Var gd,gm:integer; Procedure Run(s:string); var page:byte;x,y:integer; Begin page:=1; x:=getmaxx;y:=getmaxy div 3; Settextjustify(0,1); Setwritemode(xorput); Setactivepage(page); Repeat Outtextxy(x,y,s); Setvisualpage(page); page:=not page; setactivepage(page); delay(10); Outtextxy(x+1,y,s); x:=x-1; if x<-textwidth(s) then x:=getmaxx; Until (keypressed) and (readkey=#27); end; Begin gd:=4; Initgraph(gd,gm,'C:\BP\bgi'); setcolor(14); settextstyle(1,0,5); Run('Pham Anh Phuong'); Closegraph; End.
Bài tập 10.7: Viết chương trình vẽ mô hình chiếc đĩa bay chuyển động ngẫu nhiên trên màn hình.
Uses crt; Graph; Const r = 20; StartX = 100; StartY = 50; Procedure ThietLapDohoa; Var Gd,Gm:Integer; Begin Gd:=0; InitGraph(Gd,Gm,’D:\BP\BGI’); End; Procedure Move(Var x,y:Integer); Var Step:Integer; Begin Step:=Random(2*r); If Odd(Step) Then Step:=-Step; x:=x+Step; Step:=Random(r); If Odd(Step) Then Step:=-Step; y:=y+Step; End; Procedure VeDiaBay; Begin Ellipse(StartX,StartY,0,360,r,(r div 3)+2); Ellipse(StartX,StartY-4,190,357,r,r div 3); Line(StartX+7,StartY-6,StartX+10,StartY-12); Line(StartX-7,StartY-6,StartX-10,StartY-12); Circle(StartX+10,StartY-12,2); Circle(StartX-10,StartY-12,2); End; Procedure Play; Var x1,y1,x2,y2,size:Word; x,y:Integer; P:Pointer; Begin VeDiaBay; x1:=StartX - (r+1); y1:=StartY - 14; x2:=StartX + r + 1; y2:=StartY + (r div 3) + 3; (* Lưu và xóa ảnh *) size:=ImageSise(x1,y1,x2,y2); GetMem(p,size); GetImage(x1,y1,x2,y2,P^); PutImage(x,y,P^,XORPut); { Xóa ảnh } x:=GetMaxX div 2; y:=GetMaxY div 2; (* Di chuyển đĩa bay *) Repeat PutImage(x,y,P^,XORPut); { Vẽ đĩa bay } Delay(200); PutImage(x,y,P^,XORPut); { Xóa đĩa bay } Move(x,y); Until KeyPressed; FreeMem(p,size); { Giải phóng vùng nhớ } End; BEGIN ThietLapDoHoa; Play; CloseGraph; END.
Bài tập 10.8: Viết chương trình để vẽ đa giác đều có n đỉnh.
Ý tưởng:
Khi vẽ một đa giác đều N đỉnh, các đỉnh này nằm trên một đường tròn (O,R) đồng thời khoảng cách giữa hai đỉnh và tâm tạo thành một góc nhọn không đổi có giá trị là 2*Pi/N.
Giả sử đỉnh thứ nhất của đa giác nằm trên đường thẳng tạo với tâm một góc 00, đỉnh thứ hai tạo một góc 2*Pi/N và đỉnh thứ i sẽ tạo một góc là 2*Pi(i-1)/N.
Một cách tổng quát, ta tạo một mảng để chứa tọa độ các đỉnh.
Const Max = <Giá trị>;
Type Mang = ARRAY[1..Max] of PointType;
Var P:Mang;
Giả sử chọn P0: PointType là tọa độ tâm của đa giác thì đỉnh thứ i của đa giác sẽ tạo một góc là: Angle:=2*Pi*(i-1)/N
Nhưng nếu đa giác này có đỉnh đầu tiên tạo một góc bằng A0 thì:
Angle:=2*Pi*((i-1)/N + A0/360)
Và tọa độ các đỉnh này trên màn hình là:
P[i].x := P0.x + R*cos(Angle)
P[i].y := P0.y – R*sin(Angle)
Ta xây dựng thủ tục để tự động lưu các đỉnh của đa giác đều vào mảng P. Trong đó: P0 là tọa độ tâm, A0 là góc bắt đầu, R là bán kính, N là số đỉnh (3<N<Max).
Uses Crt,Graph; Const Max = 10; Type Mang = Array[1..Max] of PointType; Var A0,R:real; N:Byte; P0:PointType; P:Mang; Procedure ThietLapDohoa; Var Gd,Gm:Integer; Begin Gd:=0; InitGraph(Gd,Gm,’D:\BP\BGI’); End; Procedure TaoDinh(R,A0:real;N:Byte;P0:PointType;Var P:MANG); var i:Byte; Angle:real; Begin If (n<3)or(n>=Max) then Begin Writeln('Khong tao duoc tap dinh!'); Exit; End; For i:=1 to n do With P[i] do Begin Angle:=2*Pi*((i-1)/n + A0/360); x:=P0.x + Round(R*Cos(Angle)); y:=P0.y - Round(R*Sin(Angle)); End; P[n+1]:=p[1]; End; BEGIN Write(‘Nhap so dinh cua da giac deu: n= ‘); Readln(N); ThietLapDoHoa; P0.x:=GetMaxX div 2; P0.y:=GetMaxY div 2; A0:=90; R:=GetMaxY div 4; TaoDinh(R,A0,5,P0,P); DrawPoly(5,P); CloseGraph; END.
Bài tập 10.9: Viết chương trình vẽ đồ thị hàm số sau: f(x) = ax2 + bx + c.
Ý tưởng:
Bước 1: Xác định đoạn cần vẽ [Min,Max].
Bước 2: Đặt gốc tọa độ lên màn hình (x0,y0).
Chia tỉ lệ vẽ trên màn hình theo hệ sô k.
Chọn số gia dx trên đoạn cần vẽ.
Bước 3: Chọn điểm xuất phát: x = Min, tính f(x).
Đổi qua tọa độ màn hình và làm tròn:
x1:=x0 + Round(x.k);
y1:=y0 – Round(y.k);
Di chuyển đến (x1,y1): MOVETO(x1,y1);
Bước 4: Tăng x lên: x:=x + dx;
Đổi qua tọa độ màn hình và làm tròn:
x2:=x0 + Round(x.k);
y2:=y0 – Round(y.k);
Vẽ đến (x2,y2): LINETO(x2,y2);
Bước 5: Lặp lại bước 4 cho đến khi x > Max thì dừng.
Uses Crt,Graph; var a,b,c,Max,Min:real; Procedure ThietLapDohoa; Var Gd,Gm:Integer; Begin Gd:=0; InitGraph(Gd,Gm,’D:\BP\BGI’); End; Function F(x:real):real; Begin F:=a*x*x + b*x + c; End; Procedure VeDoThi(Min,Max:real); var x1,y1:integer; dx,x,k:real; x0,y0:word; Begin x0:=GetMaxX div 2; y0:=GetMaxY div 2; K:=GetMaxX/30; dx:=0.001; x:=Min; x1:=x0 + Round(x*k); y1:=y0 - Round(F(x)*k); Moveto(x1,y1); While x<Max do Begin x:=x+dx; x1:=x0 + Round(x*k); y1:=y0 - Round(F(x)*k); LineTo(x1,y1); End; End; BEGIN Write(‘Nhap a= ‘); Readln(a); Write(‘Nhap b= ‘); Readln(b); Write(‘Nhap c= ‘); Readln(c); ThietLapDoHoa; Min:=-10; Max:=10; {Vẽ trục tọa độ} Line(GetMaxX Div 2,1,GetMaxX Div 2,GetMaxY); Line(1,GetMaxY Div 2,GetMaxX,GetMaxY Div 2); VeDoThi(Min,Max); Repeat Until KeyPressed; CloseGraph; END.
Bài tập 10.10: Vẽ hình bông hoa.
Ý tưởng:
Dùng tọa độ cực. Giả sử ta có tọa độ cực trong đó:
Trục cực: Ox
Góc quay: α
thì tọa độ cực của một điểm trong mặt phẳng là cặp (x,y) với:
x = f(α).Cos(α)
y = f(α).Sin(α)
Trong đó: f(a) là phương trình do ta qui định.
Ví dụ:
f(α) = k.Cos(nα) : Hình bông hoa.
f(α) = a.α(a>0) : Đường xoắn ốc Acsimet.
f(α) = k.(1+Cos(α)): Hình trái tim.
Uses Crt,Graph; var R,chuky:real; Procedure ThietLapDohoa; Var Gd,Gm:Integer; Begin Gd:=0; InitGraph(Gd,Gm,’D:\BP\BGI’); End; Function F(R,Alpha:real):real; { Tính hàm f(a) } Begin F:=R*cos(19*Alpha/3)+5; End; Procedure VeHinh(ChuKy:real); var x1,x2,y1,y2:integer; a,Alpha,k:real; x0,y0:word; Begin x0:=GetMaxX div 2; y0:=GetMaxY div 2; K:=GetMaxX/50; a:=Pi/180; Alpha:=0; x1:=x0 + Round(F(R,Alpha)*k*cos(Alpha)); y1:=y0 - Round(F(R,Alpha)*k*sin(Alpha)); Moveto(x1,y1); While Alpha<ChuKy do Begin Alpha:=Alpha+a; x1:=x0 + Round(F(R,Alpha)*k*cos(Alpha)); y1:=y0 - Round(F(R,Alpha)*k*sin(Alpha)); LineTo(x1,y1); Delay(10); End; End; BEGIN ThietLapDoHoa; R:=15; chuky:=4*Pi; VeHinh(chuky); repeat until KeyPressed; CloseGraph; END.
Bài tập 10.11: Viết chương trình vẽ cung Koch. Các bước phát sinh của cung Koch được thực hiện trong hình sau:
- Bắt đầu từ đường ngang K0 có độ dài bằng 1.
- Để tạo cung bậc-1(gọi là K1), chia đường thành ba phần và thay đoạn giữa bằng tam giác đều có cạnh dài 1/3. Bây giờ, toàn bộ đường cong có độ dài 4/3.
- Cung bậc-2 K2 có được bằng cánh dựng tiếp các tam giác đều từ 4 đoạn của K1. Vì mỗi đoạn có độ dài tăng 4/3 lần nên toàn bộ cung dài ra 4/3 lần.
Ý tưởng:
Từ hình (b) ta thấy rằng, đầu tiên hướng vẽ quay trái 600, rồi quay phải 1200, cuối cùng quay trái 600 để trở về hướng ban đầu.
Uses Crt,Graph; Var n:Integer; Goc,length:real; Procedure ThietLapDohoa; Var gd,gm:integer; Begin gd:=0; InitGraph(gd,gm,'D:\bp\bgi'); End; Procedure Koch(dir,len:real;n:integer); const rads=0.017453293; Begin If n>0 Then Begin Koch(dir,len/3,n-1); dir:=dir+60; {Quay phải 60 độ} Koch(dir,len/3,n-1); dir:=dir-120; {Quay trái 120 độ} Koch(dir,len/3,n-1); dir:=dir+60; {Quay phải 60 độ} Koch(dir,len/3,n-1); End else LineRel(Round(len*cos(rads*dir)),Round(len*sin(rads*dir))); end; Begin ThietLapDoHoa; n:=4;= Goc:=180; Length:=150; Moveto(300,200); Koch(Goc,Length,n); Repeat until keypressed; Closegraph; END.
Bài tập 10.12: Viết chương trình tạo ra C-cung dựa trên sự tinh chế tương tự của một đoạn thẳng theo hình sau:
Ý tưởng:
Để có dạng phát sinh kế tiếp, mỗi đoạn thẳng được thay bởi một “hình gãy” gồm 2 đoạn ngắn hơn tạo với nhau một góc 900. Các đoạn mới có độ dài bằng 1/ lần đoạn ở bước trước.
Xét hướng vẽ ở một đầu của đoạn thẳng. Để vẽ hình gãy, hướng vẽ quay trái 450, vẽ một đoạn, quay phải 900, vẽ đoạn thứ hai và sau đó trở về hướng cũ bằng cách quay góc 450.
Uses graph,crt; Procedure ThietLapDohoa; Var gd,gm,gr:integer; Begin gd:=0; Initgraph(gd,gm,'D:\bp\bgi'); End; PROCEDURE VeC_Cung; Var n:Integer; Goc,length:real; Procedure Rong(dir,len:real;n:integer); const d=0.7071067; rads=0.017453293; begin if n>1 then begin dir:=dir+45; Rong(dir,len*d,n-1); dir:=dir-90; Rong(dir,len*d,n-1); dir:=dir+45; end else LineRel(Round(len*cos(rads*dir)),Round(len*sin(rads*dir))); end; Begin n:=15; Goc:=0; Length:=130; Moveto(200,200); Rong(Goc,Length,n); repeat until keypressed; End; BEGIN ThietLapDoHoa; VeC_Cung; Closegraph; END.
Bài tập 10.13: Viết chương trình vẽ tập Mandelbrot – là một hình trong mặt phẳng phức. Tập Mandelbrot được phát sinh theo công thức sau:
z → z2 + c (*)
Tập hợp Mandelbrot là tập bao gồm những số phức c sao cho z2+c vẫn hữu hạn với mọi lần lặp.
Ý tưởng:
Ta chọn số phức cố định c và tính biểu thức z2+c với z là số phức biến đổi.
Nếu chọn z = 0 thì z2+c = c. Thay z vào công thức (*) ta được c2+c.
Tiếp tục thay z bằng giá trị mới, ta lại có: (c2+c)2+c, …
Cứ như vậy, ta thu được một dãy vô hạn các số z.
Uses crt,graph; Const row=1; col=1; Var x1,y1,x2,y2,kx,ky:real; Gioihan:Byte; x0,y0:word; Diemduoi,Diemtren:Integer; Procedure ThietLapDohoa; Var gd,gm,gr:integer; Begin gd:=0; Initgraph(gd,gm,'D:\bp\bgi'); End; Procedure KhoiTao; Begin Diemduoi:=GetMaxX; Diemtren:=GetMaxY; x1:=-2; y1:=-1.25; x2:=0.5; y2:=1.25; kx:=(x2-x1)/diemduoi; ky:=(y2-y1)/diemtren; Gioihan:=50; End; Procedure ManDelbrot; var dong,cot,dem:integer; P0,Q0,Modun,x,y,Aux:real; Begin cot:=0; While cot<=diemduoi do Begin P0:=x1+cot*kx; dong:=0; While dong<=(diemtren div 2) do Begin Q0:=y1+dong*ky; x:=0; y:=0; dem:=1; Modun:=1; While (dem<=gioihan)and(modun<4) do Begin Aux:=x; x:=x*x-y*y +P0; y:=2*y*Aux + Q0; Modun:=x*x + y*y; dem:=dem+1; End; If Modun<4 Then Begin PutPixel(cot,dong,3); PutPixel(cot,diemtren-dong,3); End; dong:=dong+row; End; cot:=cot+col; End; End; Begin ThietLapDohoa; KhoiTao; Mandelbrot; readln; CloseGraph; End.
BÀI TẬP TỰ GIẢI
Bài tập 10.14: Viết chương trình vẽ bàn cờ quốc tế lên màn hình.
Bài tập 10.15: Viết chương trình vẽ một chiếc xe ô tô (theo hình dung của bạn) và cho nó chạy ngang qua màn hình.
Gợi ý:
Dùng kỹ thuật lật trong màn hình hoặc di chuyển vùng màn hình.
Bài tập 10.16: Viết chương trình vẽ lá cờ tổ quốc đang tung bay.
Gợi ý:
Dùng kỹ thuật lật trong màn hình.
Bài tập 10.17: Viết chương trình nhập vào n học sinh của một lớp học bao gồm 2 trường sau: Họ tên, điểm trung bình.
a/ Hãy thống kê số lượng học sinh giỏi, khá, trung bình và yếu.
b/ Vẽ biểu đồ thống kê số lượng học sinh giỏi, khá, trung bình và yếu theo 2 dạng: biểu đồ cột (column) và biểu đồ bánh tròn (Pie).
Bài tập 10.18: Viết chương trình để vẽ đồ thị của các hàm số sau:
a/ y = ax3 + bx2 + cx +d
b/ y = ax4 + bx3 + cx2 + dx + e
Bài tập 10.19: Hình vẽ cung Koch dựa trên 3 cạnh của tam giác đều như hình sau:
Bài tập 10.20: Viết chương trình để vẽ đường xoắn ốc.
Gợi ý:
Dùng tọa độ cực.
Bài tập 10.21: Viết chương trình vẽ cái đồng hồ đang hoạt động.
Bài tập 10.22: Viết chương trình mô phỏng chuyển động của trái đất xung quanh mặt trời và đồng thời chuyển động của mặt trăng xung quanh trái đất.
Gợi ý:
Dùng ma trận của phép quay.
Bài tập 10.23: Xây dựng một thư viện (Unit) chứa tất cả các bài tập trong chương này.
Bài tập 10.24: Viết chương trình tạo Menu đồ họa giống như các Menu trong môi trường WINDOWS (xem hình).
‹ DỮ LIỆU KIỂU CON TRỎ Lập trình hướng đối tượng Pascal – Object ›