Tải bản đầy đủ (.pdf) (35 trang)

Đồ họa máy tính - Chương 2 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.8 MB, 35 trang )

Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chương II: Công cụ đồ họa của Turbo Pascal (TP)
1. Giới thiệu
- Thiết bị phần cứng điều khiển việc hiển thị hình ảnh lên màn hình có tên là Video Card
(chúng ta hay gọi là “card màn hình”).
- Có nhiều loại Card màn hình với khả năng mạnh yếu khác nhau, mỗi loại cần driver (trình
điều khiển) riêng. Bảng sau là các file driver của TP.
File driver
CGA
HERC.BGI
EGAVGA.BGI

Kiểu Video card
IBM CGA , chỉ hiển thị được 4 màu
HERCULES MONOCHROME, 2 màu
VGA và đại đa số các card màn hình
hiện nay.
Có 16 màu. Độ phân giải 640 * 480

Chúng ta sẽ
chỉ dùng loại
mạnh nhất
này

2. Phải làm gì để khởi tạo chế độ đồ họa ?
Chúng ta sẽ lập trình đồ họa bằng TP. Muốn vậy cần phải:
-

Có các file: EGAVGA.BGI, GRAPH.TPU (thư viện chứa các lệnh vẽ đồ họa) và các
file cơ bản của TP.


Đặt chúng ở cùng 1 thư mục (nếu khơng thì phải lập đường dẫn cho GRAPH.TPU tại
Option/Directory/Unit directory và cho EGAVGA.BGI bằng InitGraph)
Đặt lệnh khởi tạo chế độ đồ họa (InitGraph) vào trong chương trình

Ví dụ: Cách đơn giản và hay dùng nhất để khởi tạo đồ họa

Uses Graph;
Var
hằng đ/n
gd,gm: integer;
sẵn
Begin
xâu rỗng
gd:=detect;
InitGraph(gd,gm,”);
..........
..........
.......... /* Các lệnh đồ họa vẽ, xóa ... */
CloseGraph; /* kết thúc đồ họa, quay về chế độ màn hình văn bản bình thường */
End.
Vì sao lại là “đơn giản và hay dùng nhất” ?
- Không cần gõ vị trí tệp BGI
- Khơng cần nhớ bảng giá trị các chế độ màn hình (có khoảng hơn 10 cặp giá trị khác
nhau tương ứng với các chế độ màn hình khác nhau như EGA, HERCULES, VGA
...)


4



Đồ họa máy tính - Khoa CNTT - ĐHSPHN

-

Ln ln khởi tạo được chế độ mạnh nhất VGA (16 màu, độ phân giải 640 * 480).
Trong các phần tiếp theo ta luôn giả thiết rằng chế độ đồ họa là VGA

Chỉ để tham khảo: bảng các loại graphics card và chế độ đồ họa tương ứng
GraphDriver
CGA
--EGA
--VGA
----HercMono
...
có tổng cộng 8 giá
trị GraphDriver
khác nhau

GraphMode
CGA0
CGAHi
EGALo
EGAHi
VGALo
VGAMed
VGAHi
HercMonoHi
...
có tổng cộng 30 giá
trị GraphMode khác

nhau

Số dịng, cột
320 * 200
640 * 200
640 * 200
640 * 350
640 * 200
640 * 350
640 * 480
720 * 348
...

Chúng ta sẽ
chỉ dùng loại
mạnh nhất
này

3. Hệ trục tọa độ màn hình

(0,0)

(639,0)

(0,479)

(639,479)

Trong chế độ đồ họa, chúng ta phải làm việc với một hệ trục tọa độ khác thường:
1) Trục tung Oy quay xuống dưới (hệ trục Decac nghịch)

2) các giá trị tọa độ phải là các số nguyên
3) Nếu tọa độ vượt ra ngoài khoảng (0,639) đối với hoành độ và (0,479) đối với tung
độ, thì những gì ta vẽ sẽ khơng hiển thị trên màn hình
Giải thích:
1) Do cấu tạo của màn hình, ta phải chấp nhận.
2) Màn hình chia thành nhiều ơ vng nhỏ (pixel) sắp xếp theo từng dịng và cột như
hình vẽ.
3) Giả sử ta vẽ đoạn thẳng AB, thì chỉ có đoạn CD nằm trong màn hình được hiển thị


5


Đồ họa máy tính - Khoa CNTT - ĐHSPHN
B
D
C

Màn hình

A

Chú ý: chúng ta không cần nhớ 2 giá trị 640 và 480 vì TP đã có 2 hàm GetMaxX và
GetMaxY, chúng trả lại giá trị lớn nhất của hoành độ và tung độ đối với mode đồ họa hiện
thời: GetMaxX = 639 ; GetMaxY = 479 ;

639,0

0,0 1,0 2,0 ...
0,1

0,2
...

mỗi điểm ảnh là
1 ô vuông

0,479

4. Bảng màu
Với mode đồ họa VGA, bảng màu gồm 16 màu được đánh số từ 0 đến 15 như trong bảng
sau. Ta có thể dùng số thứ tự hoặc tên hằng số chỉ màu
Giá trị số
0
1
2
3
4
5
6
7
8
9

Tên hằng số
Black
Blue
Green
Cyan
Red
Magenta

Brown
LightGray
DarrkGray
LightBlue



Màu
Đen
Xanh da trời
Xanh lá cây
Xanh cẩm thạch
Đỏ
Tía
Nâu
Xám nhạt
Xám đậm
Xanh da trời nhạt
6


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

10
11
12
13
14
15


LightGreen
LightCyan
LightRed
LightMagenta
Yellow
White

Xanh lá cây nhạt
Xanh cẩm thạch nhạt
Đỏ tươi
Tía nhạt
Vàng
Trắng

5. Vẽ điểm
PutPixel(x,y,c); /* x,y : integer ; c: word (kiểu số nguyên dương) */
Vẽ 1 điểm ảnh tại tọa độ (x,y) với màu c,
GetPixel(x,y):word
Hàm GetPixel trả lại một số nguyên dương là màu của điểm ảnh ở tọa độ (x,y), nói cách
khác nó cho biết màu của pixel(x,y) là màu gì.
Ví dụ: Tơ tồn màn hình bằng màu đỏ

Uses Graph;
Var
gd,gm: integer;
i,j:integer;
Begin
gd:=detect;
InitGraph(gd,gm,”);
for i:=0 to GetMaxX do

for j:=0 to GetMaxY do
PutPixel(i,j,red) ;
Readkey;
/* Gặp readkey chương trình sẽ dừng lại để ta quan sát màn hình. Xem xong ta bấm
phím bất kỳ để qua lệnh này */
CloseGraph;
End.
Những hằng, biến nào trong chương trình trên có thể được thay bằng những giá trị tương
đương mà không làm thay đổi chương trình ?
Viết chương trình tơ một phần tư màn hình (phía trên bên phải) bằng màu xanh da trời
Chương trình trên lấp kín màn hình bằng cách tơ theo dịng hay cột ?



7


Đồ họa máy tính - Khoa CNTT - ĐHSPHN
Ví dụ: vẽ lưới điểm nhấp nháy

uses crt,graph;
var
gd,gm,i,j:integer;
x,y:integer;
begin
gd:=detect; initgraph(gd,gm,'');
randomize; /* khởi tạo bộ sinh số ngẫu nhiên */
repeat
Hàm trả lại số màu
x:=random(100); y:=random(100);

hiện có (16)
if GetPixel(x,y) <>0 then
Putpixel(x,y,0)
else PutPixel(x,y,random(GetmaxColor));
delay(2);
Until Keypressed;
closegraph;
end.
Hàm GetPixel làm chức năng gì trong ví dụ trên ?
Thử thay đổi giá trị tham số của hàm delay() và random() và quan sát kết quả
Ví dụ: Vẽ bầu trời sao đơn giản

uses crt,graph;
var gd, gm, i : integer;
BEGIN
gd := 0; initgraph(gd,gm,'C:\TP\BGI');
for i := 1 to 1000 do
putpixel(random(640),random(480),random(15)+1);
readkey;
END.
Hãy phối hợp những kỹ thuật trong 2 ví dụ trên ( hàm random, vịng lặp Repeat, lệnh
GetPixel để tạo ra bầu trời sao đẹp hơn
Ví dụ: Vẽ đồ thị hàm số y=sin(x)

Uses crt,graph;
Var
tx,ty,gd,gm,i,j:integer;
d,x,y:real;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');

setviewport(getmaxX div 2,getmaxY div 2,getmaxX,getmaxY,clipoff);


8


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

d:=0.001; x:=0; tx:=20; ty:=40;
while x<4*pi do
begin
putpixel(round(tx*x),-round(ty*sin(x)),yellow);
x:=x+d;
end;
readln;
closegraph;
End.
Hãy giải thích ý nghĩa của tx,ty,d ?
Nếu gán d:=0.5 thì kết quả thay đổi ra sao ?
Vì sao phải có dấu trừ trong tham số thứ 2 của PutPixel ? Nếu bỏ dấu trừ đi thì kết quả ra
sao ?
Hãy vẽ đồ thị hàm số y = x2 – 2x +1 trong khoảng [-3,3]
Hãy vẽ đồ thị hàm số y = sin 2x trong khoảng [-2π, 2π]

6. Vẽ đoạn thẳng
Line(x1,y1,x2,y2) /* x1,x2,y1,y2: integer */
Vẽ đoạn thẳng nối (x1,y1) với (x2,y2) bằng màu vẽ hiện thời ấn định bởi lệnh SetColor gần
nhất. Nếu khơng có lệnh SetColor nào thì màu vẽ mặc định ln là màu Trắng (white).
Trước lệnh vẽ đoạn thẳng ta nên đặt màu vẽ cho lệnh Line bằng lệnh
SetColor (c); /* c: word */

Hãy vẽ thêm 2 trục tọa độ cho ví dụ mẫu vẽ đồ thị hàm sin ở mục trên
Hãy làm lại ví dụ “Tơ tồn màn hình bằng màu đỏ” nhưng dùng lệnh Line thay cho
PutPixel
Hãy tơ kín hình chữ nhật (50,50,100,100) bằng cách dùng lệnh Line
50,50

100,100

Vẽ và lấp đầy một hình bình hành bằng các đoạn thẳng xiên như hình (a). Có thể lấp đầy
bằng các đoạn thẳng nằm ngang như hình (b) được khơng ?



9


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

(a)

(b)

Biết rằng trên màn hình màu đen chỉ có 1 tam giác màu trắng có vị trí và hình dạng bất
kỳ. Hãy đếm xem có bao nhiêu điểm ảnh nằm bên trong tam giác đó (khơng tính các cạnh) ?

Hãy vẽ lại đồ thị hàm y = sin(x) nhưng thay vì chấm từng điểm ảnh như ở ví dụ trên thì
ta nối điểm ảnh này với pixel tiếp theo.
Ngồi ra cịn có 2 lệnh vẽ đoạn thẳng khác
LineTo(x,y) /* x,y: integer */
LineRel(dx,dy) /* x1,x2,y1,y2: integer */

Lệnh LineTo(x,y) vẽ đoạn thẳng nối CP hiện thời (xem khái niệm CP ở phần sau) với điểm
(x,y), nói cách khác
Line(x1,y1,x2,y2);
tương đương với 2 lệnh:
MoveTo(x1,y1); LineTo(x2,y2);
Cịn LineRel(dx,dy) vẽ đoạn thẳng từ CP đến 1 điểm có độ chênh là (dx,dy), nói cách khác:
LineRel(dx,dy)
tương đương với
Line(GetX,GetY,GetX+dx,GetY+dy);
Thiết lập dạng đoạn thẳng
SetLineStyle(dạng,mẫu-tự-tạo,bềdày); { ta bỏ qua mẫu_tự_tạo bằng cách cho 1 giá trị
nguyên tùy ý}
Dạng:
SolidLn
DottedLn


0
1

Nét Đặc
Nét chấm chấm
10


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

CenterLn
DashedLn


2
3

Nét chấm gạch
Nét đứt đoạn

Bề dày có thể nhận giá trị từ 1 (bình thường) đến 3 (nét đậm).
7. Thiết lập chế độ vẽ đè
SetWriteMode (mode); /* mode: word */
Mode
CopyPut
XorPut

Giá trị số
0
1

Tác dụng
Vẽ hình mới đè lên hình cũ (chế độ vẽ bình thường)
Màu của từng pixel sẽ được Xor với màu cũ

Trong chế độ XorPut, giá trị màu vẽ và màu nền được nhị phân hóa, sau đó làm phép Xor
với nhau để ra màu hiển thị.
Xor
0
1

0
0
1


1
1
0

Lệnh SetWriteMode có tác động tới các lệnh vẽ đường như: Line, LineTo, LineRel,
Rectangle, DrawPoly ... và không tác động tới các lệnh vẽ đường trịn, elip ...
Ví dụ: Minh họa chế độ xorput

Uses Graph;
Var
gd,gm: integer;
i,j:integer;
Begin
gd:=detect;
InitGraph(gd,gm,”);
SetFillStyle(1,Brown); /* đặt chế độ tô đặc với màu tô là nâu */
Bar(100,100,200,200); /* Vẽ hình vng màu nâu */
Readkey;
SetColor(white);
SetWriteMode(XorPut);
for i:=100 to 200 do line(100,i,200,i) ; /* hình vng đổi thành màu gì ? */
Readkey;
CloseGraph;
End.
Sau lệnh Readkey thứ nhất chương trình dừng lại, lúc đó trên màn hình có gì ?
Sau lệnh Readkey thứ 2 chương trình dừng lại, lúc đó trên màn hình có gì ? Tại sao ?


11



Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Chế độ XorPut đặc biệt hay được dùng để vẽ hình chuyển động vì dù hình mới là gì thì sau
2 lần vẽ đè với XorPut hình cũ cũng sẽ được khơi phục ngun trạng (vẽ hình chuyển động
khơng để lại vết)
Giải thích nhận định trên
8. Cửa sổ ViewPort của TP
ViewPort (của đồ họa Pascal) là 1 vùng hình chữ nhật trên màn hình. Để thiết lập ViewPort
ta dùng lệnh:
SetViewPort(x1,y1,x2,y2,clip);
x1,x2,y1,y2: tọa độ của ViewPort; clip = true (không cho phép vẽ ra ngoài) hoặc false.
Chú ý là sau khi đã thiết lập ViewPort thì gốc tọa độ được tự động chuyển về (x1,y1).

ViewPort: clip=off

ViewPort: clip=on

Xóa nội dung bên trong ViewPort: ClearViewPort;
Loại bỏ hẳn ViewPort, trở về chế độ làm việc toàn màn hình: ClearDevice; Lệnh này cũng
dùng để xóa màn hình và đưa CP về (0,0)
9. Con trỏ trong chế độ đồ họa (CP: Current Pointer)
Ta khơng nhìn thấy CP trên màn hình, nhưng TP ln theo dõi vị trí của CP bằng cặp hàm
GetX, GetY: trả lại tọa độ hiện thời của CP
Moveto(x,y): di chuyển CP tới (x,y)
MoveRel(dx,dy): di chuyển CP tới vị trí mới cách vị trí cũ 1 độ chênh là (dx,dy)
dx
O


dy

x

Moverel (dx,dy)

(x1,y1)

(x2,y2)

y


12


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Lệnh có liên quan đến CP:
- LineTo(x,y): vẽ đoạn thẳng nối từ CP đến (x,y), đồng thời chuyển CP đến đó.
- LineRel(dx,dy): vẽ đoạn thẳng nối từ CP đến vị trí mới có độ chênh là (dx,dy) và
kéo CP tới đó.
10. Vẽ hình chữ nhật
Vẽ hình chữ nhật có đỉnh trên bên trái là (x1,y1), đỉnh dưới phải (x2,y2) và các cạnh song
song với 2 trục:
Rectangle(x1,y1,x2,y2); /* x1,y1,x2,y2: integer */
Để vẽ và tơ hình chữ nhật đặc ta dùng Bar(x1,y1,x2,y2); /* x1,y1,x2,y2: integer */
màu tô và mẫu tô phải được thiết lập từ trước bằng lệnh
SetFillStyle(Pattern, Color);
Pattern

EmptyFill
SolidFill
LineFill
LtSlashFill
Slashfill
....
UserFill

Giá trị số
0
1
2
3
4
...
12

Mẫu tô
Màu nền (= để trống)
Màu đặc
Gạch dọc
Tô sọc chéo thưa
Tô sọc chéo dày
người lập trình tự định nghĩa bằng lệnh SetFillPattern()

Lệnh SetFillStyle() đặt mẫu tơ cho các lệnh tơ hình kín như:
• Rectangle: hình chữ nhật
• Bar: hình chữ nhật đặc
• Bar3D: hình hộp
• FillPoly: đa giác

• PieSlice: quạt trịn

Ví dụ: Vẽ bàn cờ

uses crt,graph;
const stop=50;
var


13


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

gd,gm,i,j,cạnh,a,màu:integer;
Begin
canh:=40;
a:= 100;
gd:=detect; initgraph(gd,gm,'');
màu:=white;
setlinestyle(1,1,3);
rectangle(a,a,a+8*canh,a+8*canh); {vẽ khung bàn cờ bằng đường đứt đoạn}
for i:=0 to 7 do
for j:=0 to 7 do
begin
setfillstyle(1,mau);
bar(a+i*canh,a+j*canh,a+(i+1)*canh,a+(j+1)*canh); {1}
if j<>7 then {ô dưới cùng của một cột}
if mau=white then mau:= black else mau:=white; {2}
end;

readkey;
closegraph;
end.
Giải thích ý nghĩa của biến a, canh, i,j trong chương trình trên ? Các lệnh {1}, {2} có tác
dụng gì ?
Đoạn trình sau có vẽ được bàn cờ không ?
for i:=0 to 7 do
for j:=0 to 7 do
begin
if (i+j) mod 2 =0 then mau:=white else mau:= black;
setfillstyle(1,mau);
bar(a+i*canh,a+j*canh,a+(i+1)*canh,a+(j+1)*canh);
end;
Vẽ các hình chữ nhật có vị trí và kích thước ngẫu nhiên (có các cạnh nằm ngang hoặc
thẳng đứng như hình (a)
Vẽ các hình chữ nhật ngẫu nhiên (các cạnh có thể nghiêng tùy ý kiểu như hình (b)

(b)

(a)


14


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Hãy vẽ một hình vng ở tâm màn hình, cho nó từ từ phình to ra đến khi chạm rìa màn
hình thì dừng lại. Sau đó co lại để trở về kích thước ban đầu.


11. Đa giác
Vẽ đa giác
DrawPoly(n,P);
n: số đỉnh đa giác +1
P: tham số chứa tọa độ các đỉnh của đa giác
Tô đa giác bằng lệnh sau:
FillPoly(n,P); /* n và P như trên. Chú ý là n không cần cộng 1*/
Xem các ví dụ sau để hiểu rõ
Ví dụ: Vẽ các ngũ giác ngẫu nhiên

Uses crt,graph;
Type
Dinh = Record /* Đỉnh đa giác */
x,y:integer;
End;
Var
gd,gm:integer;
i:integer;
dagiac: array[1..6] of Dinh;
Begin
gd:=detect;
InitGraph(gd,gm,'');
Randomize;
Repeat
SetColor(random(GetMaxColor));


/* màu được chọn ngẫu nhiên */
15



Đồ họa máy tính - Khoa CNTT - ĐHSPHN

for i:=1 to 5 do
begin
dagiac[i].x:=random(getMaxX);
dagiac[i].y:=random(getMaxY);
end;
dagiac[6]:=dagiac[1];
DrawPoly(6,dagiac);
Delay(1000);
Until KeyPressed;
CloseGraph;
End.

/* tọa độ đỉnh được chọn ngẫu nhiên */

Chú ý lệnh dagiac[6]:=dagiac[1] . Để vẽ đa giác kín N đỉnh ta phải tạo ra đỉnh thứ N+1
trùng với đỉnh đầu.
Các đa giác trong chương trình trên đè chồng lên nhau và làm đầy màn hình. Hãy sửa
chương trình để chúng hiện lên rồi tự tắt. Hãy sửa để ln ln lưu lại trên màn hình 3 đa
giác mới nhất.
Ví dụ: Vẽ và tơ các ngũ giác ngẫu nhiên

Uses crt,graph;
Type
Dinh = Record
x,y:integer;
End;
Var

gd,gm:integer;
i:integer;
dagiac: array[1..6] of Dinh;
Begin
gd:=detect;
InitGraph(gd,gm,'');
Randomize;
Repeat
SetColor(random(GetMaxColor));
SetFillStyle(SolidFill,random(GetMaxColor));
for i:=1 to 5 do
begin
dagiac[i].x:=random(getMaxX);
dagiac[i].y:=random(getMaxy);
end;
dagiac[6]:=dagiac[1];
DrawPoly(6,dagiac);
FillPoly(6,dagiac);
Delay(2000);
Until KeyPressed;
CloseGraph;


16


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

End.
Chú ý quan sát ta thấy, với các đa giác lõm lệnh FillPoly tính tốn tất cả các chỗ tự cắt và

sau đó tơ riêng từng phần. Màu tơ và mẫu tơ xác định bởi SetFillStyle. Dưới đây là 1 ngũ
giác lõm với các cạnh tự cắt được tô bởi FillPoly

12. Tô màu miền kín
FloodFill(x,y,color); /* x,y : integer; c: word */
Vùng cần tô được nhận dạng nhờ 2 yếu tố:
- đường biên khép kín có màu color
- điểm (x,y) là một điểm bất kỳ nằm bên trong vùng cần tô.
Màu tô và mẫu tơ được ấn định bởi SetFillStyle
(x,y)
(x,y)

Ví dụ: VẼ LÁ CỜ ĐỎ SAO VÀNG

uses crt,graph;
var gd, gm, i, goc, r : integer;
p : array[1..5,1..2] of integer; { toạ độ các đỉnh ngôi sao }
BEGIN
gd := 0; initgraph(gd,gm,'');
goc := 18; r := 100;
for i := 1 to 5 do begin
p[i,1] := round(r*cos(goc*pi/180)); { hoành độ của đỉnh thứ i }
p[i,2] := - round(r*sin(goc*pi/180)); { tung độ của đỉnh thứ i }
goc := goc + 2*72;
end;


17



Đồ họa máy tính - Khoa CNTT - ĐHSPHN

SetFillStyle(1,red);
{vẽ lá cờ là hình chữ nhật màu đỏ}
Bar(100,100,540,380);
SetViewPort(320,240,600,400,false); {chuyển gốc toạ độ ra giữa màn hình}
SetColor(yellow);
SetFillStyle(1,yellow);
FillPoly(5,p);
{2 lệnh này tơ hình ngơi sao vàng }
FloodFill(0,0,yellow);
readkey;
END.
Vì sao trong cơng thức tính tung độ đỉnh thứ i của ngơi sao lại có dấu trừ ? Nếu bỏ dấu
trừ này đi thì hiện tượng gì xảy ra ?
Vì sao phải cần 2 lệnh mới tơ được ngơi sao ? Nếu bỏ lệnh FloodFill đi thì kết quả sẽ ra
sao ? Hoặc nếu chỉ bỏ đi lệnh FillPoly thì trên màn hình sẽ có gì ?
Lệnh FillPoly ở trên tơ màu một ngũ giác, đó là ngũ giác nào ?
Giải thích các lệnh: goc := 18; goc := goc + 2*72;
Vì sao khơng vẽ và tơ đa giác 10 đỉnh (123456789-10) ? thay vào đó ví dụ trên vẽ đa
giác nào ?
y
1

A
B

E

3


180
O
C

2

10

4

x
D

9
8

6

5

7

13. Vẽ cung, đường tròn
Vẽ cung tròn:

A

Arc(x,y, g1,g2,r);


B

g2
g1

x,y: integer - tọa độ tâm đường tròn
g1,g2: word – góc bắt đầu và góc cuối
của cung trịn (tính bằng độ)
r: word – bán kính

O

Để vẽ hình quạt trịn, đầu tiên ta vẽ cung trịn, sau đó gọi thủ tục
GetArcCoords(VAR ArcCoords: ArcCoodsType);
để lấy tọa độ 2 đầu mút (A,B) của cung.Cuối cùng ta vẽ hai đoạn thẳng nối chúng với tâm O
của đường tròn
Với kiểu ArcCoodsType được định nghĩa như sau:
Type


18


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

ArcCoodsType = RECORD
x,y:integer;
xStart,yStart:integer;
xEnd,yEnd:integer;
END

trong đó (x,y) là tọa độ tâm O, (xStart,yStart) là tọa độ điểm đầu B của cung, (xEnd,yEnd)
là điểm cuối A.
Ví dụ: Vẽ quạt trịn

uses crt,graph;
var
gd,gm:integer;
a:ArcCoordsType;
x,y,g1,g2,r: integer;
Begin
gd:=detect; initgraph(gd,gm,'');
x:=GetMaxX div 2; y:=GetMaxY div 2; { tâm đặt chính giữa màn hình }
g1:=30; g2:=330;
{góc bắt đầu, góc kết thúc }
r:=100;
arc(x,y,30,330,100);
GetArcCoords(a);
line(x,y,a.xStart,a.yStart);
line(x,y,a.xEnd,a.yEnd);
readkey;
closegraph;
End.
Cải tiến chương trình trên để vẽ đầu cá đóng - mở miệng liên tục
Viết chương trình vẽ hình trăng lưỡi liềm và khun

Vẽ đường trịn tâm (x,y) bán kính r :
Circle(x,y,r); /* x,y: integer; r: word */
Vẽ cung elip tâm (x,y), bán trục lớn xr, bán trục bé yr, góc bắt đầu và góc kết thúc là g1,g2
Ellipse(x,y,g1,g2,xr,yr)




19


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

yr
xr

Vẽ và tơ hình quạt trịn:
PieSlice(x,y, g1,g2, r);
Ý nghĩa các tham số giống như lệnh Arc
Để tô màu ellip, cũng như đường trịn, ta dùng thủ tục:
FillEllipse(x,y,xr,yr); {x,y:integer; xr,yr: word}
Để tơ một cung ellip ta gọi thủ tục
Sector(x,y,StAngle,EndAngle,xr,yr); {x,y: integer; StAngle,EndAngle, xr,yr: word}

Ví dụ: VẼ BĨNG CHUYỂN ĐỘNG KIỂU BẬT TƯỜNG

uses crt,graph;
var gd,gm,x,y,dx,dy,r : integer;
BEGIN
gd := 0; initgraph(gd,gm,'');
x := 100; y := 100; dx := -6; dy := 5; r := 30;
repeat
setcolor(yellow);
circle(x,y,r); {vẽ đường tròn màu vàng}
delay(20);
setcolor(0);

circle(x,y,r); {vẽ đường tròn màu trùng màu nền <=> xoá }


20


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

if (x>=640-r) or (x{nếu chạm cạnh trái/phải thì đổi hướng}
if (y>=480-r) or (y{nếu chạm cạnh trên/dưới thì đổi hướng}
x := x + dx; y := y + dy;
{cập nhật toạ độ}
until keypressed;
{có phím nhấn thì dừng}
END.
Vị trí xuất phát, kích thước bóng là gì ? biến nào quy định hướng xuất phát của bóng ?
Chương trình trên dùng kỹ thuật gì để vẽ hình chuyển động ?
Làm sao để tăng/giảm tốc độ bóng ?
Ví dụ: Vẽ đồng hồ với kim giây chuyển động

Uses crt,graph;
Var
gd,gm:integer;
x,y,a,b,r:integer;
c,i,x1,x2,y1,y2:integer;
g,d:real;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');

a:=GetMaxX div 2; b:=GetmaxY div 2;
Setcolor(Yellow);
SetWriteMode(Xorput);
r:=150;
Circle(a,b,r);
{Vẽ các vạch chia}
c:=5; {chiều dài ½ vạch chia}
d:=pi/6; g:=0;
while g< 2*pi do
begin
g:=g+d;
x1:=a+round((r-c)*cos(g));
x2:=a+round((r+c)*cos(g));
y1:=b-round((r-c)*sin(g));
y2:=b-round((r+c)*sin(g));
line(x1,y1,x2,y2); {Vẽ vạch chia}
end;
{Vẽ kim giây chuyển động}
x:=a; y:=b-r; line(a,b,x,y);
g:=pi/2; d:=pi/30;
repeat
line(a,b,x,y);
g:=g-d;
x:=round(a+r*cos(g)); y:=round(b-r*sin(g));
line(a,b,x,y);
delay(1000);
until KeyPressed;
closegraph;
End.



21


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Ý nghĩa các biến a,b,x,y, r, d là gì ?
Chương trình trên dùng kỹ thuật gì để vẽ kim giây chuyển động ?
Nếu là vẽ kim phút thì phải sửa chương trình trên như thế nào ?
Hãy vẽ đồng hồ với 2 kim cùng chuyển động: kim giây và kim 1/10 giây
14. Viết chữ

(x,y)

OutText(s);
{s: string}
OutTextXY(x,y,s); {x,y:integer; s: string}

ABCDEFG

Lệnh OutText(s) hiển thị xâu ký tự s tại vị trí CP, khơng di chuyển CP. Lệnh OutTextXY
hiển thị xâu ký tự s tại vị trí (x,y)
Các phơng chữ (font) khác nhau nằm trên các file *.CHR, nên để chúng tại cùng vị trí với
file *.BGI. Chọn kiểu font chữ bằng lệnh sau:
SetTextStyle(Font, Direction, Size);
Tham số font nhận các giá trị sau
Tên font
DefaultFont
TriplexFont
SmallFont

SansSerifFont
GothicFont

Giá trị số
0
1
2
3
4

Tham số Direction nhận các giá trị sau
Chiều viết Giá trị
Tác dụng
số
HorizDir 0
viết ngang
VertDir
1
viết theo chiều
thẳng đứng

Hệ số phóng to Size nhận các giá trị từ 1 đến 10.
Ví dụ: Vẽ chữ có bóng

uses crt,graph;
Var
gd,gm,i:integer;
Begin
gd:=detect; initgraph(gd,gm,'');
setTextStyle(GothicFont,0,10);

SetColor(DarkGray);
{1}
for i:=1 to 10 do outTextxy(100+i,100-i,'Graphic');
SetColor(LightGray);
{2}
outTextxy(100,100,'Graphic');
readln;


22


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

closegraph;
End.
Màu chữ và màu bóng có giống nhau khơng ? giải thích tác dụng của lệnh {1} và {2} ?
nếu hoán vị 2 lệnh đó thì sao ?
Làm sao để điều khiển chữ đổ bóng sang hướng trái/phải, lên trên/xuống dưới như các
hình dưới đây?

Viết chương trình để các dịng chữ chuyển động từ hai bên ra giữa / rơi từ trên xuống ...
15. Cắt dán hình
Để lưu một hình vào bộ nhớ, ta phải lưu cả diện tích hình chữ nhật bao nó
Memory
(x1,y1)

ABC

(x2,y2)


Để tính tốn kích thước vùng nhớ cần dùng để chứa hình, ta gọi hàm
ImageSize(x1,y1,x2,y2) ; {x1,y1,x2,y2: integer }
với (x1,y1,x2,y2) là tọa độ hình chữ nhật bao quanh hình cần lưu trữ. Chú ý là TP không
cho phép lưu trữ một hình có diện tích q lớn.
Sau đó, ta xin trình dịch cấp phát vùng nhớ này bằng cách gọi thủ tục
GetMem(p: pointer, n: word) ;
Thủ tục này xin cấp phát 1 vùng nhớ n byte (n phải được dự trù trước bằng cách gọi hàm
ImageSize), rồi lưu địa chỉ vùng nhớ đó vào con trỏ p. Chú ý: sau khi dùng xong nên giải


23


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

phóng vùng nhớ này bằng FreeMem(p,n); nếu không sau vài lần gọi GetMem sẽ cạn dung
lượng nhớ.
Bước tiếp theo, ta dùng thủ tục
GetImage(x1,y1,x2,y2, p) ; {x1,y1,x2,y2: integer ; p: pointer}
để sao chép các điểm ảnh trên màn hình nằm trong phạm vi hình chữ nhật (x1,y1,x2,y2) vào
vùng nhớ xác định bởi con trỏ p;
Khi cần thiết, ta dán ảnh đang lưu trong bộ nhớ ra màn hình bằng thủ tục
PutImage(x,y,p,mode); {x,y: integer; p: pointer; mode: word}
Lệnh này sẽ copy ảnh đang lưu trong bộ nhớ xác định bởi p vào vị trí (x,y) theo kiểu mode
Tham số mode nhận các giá trị như sau
Mode
CopyPut
XorPut


Giá trị số
0
1

Tác dụng
Vẽ hình mới đè lên hình cũ
Màu của từng pixel sẽ được Xor với màu cũ

Ví dụ: Cắt dán ảnh

uses crt,graph;
var
gd,gm:integer;
i,x,y,dx,dy,canh:integer;
p:pointer; {con trỏ trỏ tới vùng nhớ dùng để cất giữ ảnh}
size:word;
Begin
gd:=detect; initgraph(gd,gm,'');


24


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

randomize;
dx:= GetMaxX div 2; dy:= GetMaxY div 2;
SetViewPort(0,0,dx,dy,true);
for i:=1 to 40 do {Vẽ các vòng tròn ngẫu nhiên trong phần tư màn hình trên bên trái}
begin

x:=random(dx); y:=random(dy);
SetColor(random(GetMaxColor));
circle(x,y,random(dy));
end;
SetViewPort(0,0,GetMaxX,GetMaxY,false);
SetColor(White);
x:=50; y:=50; canh:=100; {ảnh cần lưu là 1 hình vng cạnh dài 100 pixel}
Rectangle(x,y,x+canh,y+canh); {vẽ đường bao quanh phạm vi ảnh cần lưu}
Size:=ImageSize(x,y,x+canh,y+canh);
GetMem(p,size);
GetImage(x,y,x+canh,y+canh,p^);
PutImage(x+dx,y,p^,CopyPut);
readkey;
closegraph;
End.
Giải thích ý nghĩa của các biến: canh,x,y. Tác dụng của 2 lệnh SetViewPort trong
chương trình trên là gì ? thử thay đổi giá trị tham số cuối cùng (tham số boolean) của chúng
và quan sát kết quả
Nếu thay CopyPut bằng XorPut trong lệnh PutImage(x+dx,y,p^,CopyPut); thì có gì thay
đổi khơng ? Vì sao ?
16. Nhận biết phím được ấn
Trong khi chương trình đang chạy, người dùng có thể ấn các phím để điều khiển (ví
dụ trong các game sử dụng bàn phím để điều khiển hành động của nhân vật). Để nhận biết
phím nào được ấn, một trong những kỹ thuật TP hay sử dụng là dùng hàm Readkey. Đối với
những phím đặc biệt như các phím mũi tên, lần đọc bằng Readkey thứ nhất sẽ trả lại giá trị
0 để ta nhận biết đó là phím mở rộng, lần Readkey thứ hai mới đọc ra mã qt mở rộng của
chúng phím đó. Đối với phím bình thường (như Esc, các phím chữ cái ... ) thì chỉ cần một
lần đọc bằng Readkey.
Ví dụ: Hộp chuyển động theo sự điều khiển của người dùng


{Hộp vng dịch chuyển theo phím mũi tên mà người dùng bấm}
Uses crt,graph;
Var
gd,gm:integer;
canh,x,y,d:integer;
ch:char;
Procedure hộp(x,y:integer);
Begin
rectangle(x-canh,y-canh,x+canh,y+canh);
{Vẽ hộp}


25


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

delay(d);
rectangle(x-canh,y-canh,x+canh,y+canh);

{Xóa hộp}

End;
Begin
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
x:=100; y:=100;
{Vị trí ban đầu của hộp }
setWriteMode(xorput);
d:=50; canh:=10;
Repeat

Repeat
hộp(x,y);
Until Keypressed;
ch:=readkey;
if ch=#0 then
{một phím mở rộng đã được ấn }
begin
ch:=readkey;
case ch of
#72: y:=y-10; {phím }
#80: y:=y+10; {phím }
#75: x:=x-10; {phím }
#77: x:=x+10; {phím }
end;
end;
Until ch=#27;
{phím ESC}
closegraph;
End.
Giải thích ý nghĩa của các biến: canh, ch, x,y
Chương trình trên dùng kỹ thuật gì để vẽ hộp chuyển động ?
Chương trình trên quy định phím nào là phím kết thúc chương trình ? Hãy viết lại
chương trình để nó coi phím chữ a là phím kết thúc (mã ASCII của chữ a là 65)
Quan sát ta thấy nếu hộp di chuyển ra ngoài màn hình thì nó biến mất. Hãy sửa chương
trình để nó khơng thể chạy vượt ra khỏi phạm vi màn hình (dừng lại khi ra đến mép, hoặc
chạm vào mép và bắt đầu chạy ngược lại)
17. Các kỹ thuật đồ họa cơ bản và minh họa




26


Đồ họa máy tính - Khoa CNTT - ĐHSPHN
Ví dụ: VẼ BÁNH XE LĂN (1)

uses crt,graph;
var gd,gm,x,y,dx,da,r,a : integer;
procedure banhxe(x,y,r,c,n,a : integer);
{vẽ bánh xe có n nan hoa với màu c}
var goc,dx,dy,i : integer;
{a là góc của nan hoa đầu tiên}
begin
SetColor(c); goc := a;
circle(x,y,r);
for i := 1 to n do begin
dx := round(r* cos(goc * pi/180)); {dx, dy là toạ độ tương đối của đầu nan hoa}
dy :=-round(r* sin(goc * pi/180));
line(x,y,x+dx,y+dy);
goc := goc + 360 div n;
end;
end;
BEGIN
gd := 0; initgraph(gd,gm,'');
x := 30; y := 200; dx := 3; a := 30; r := 30; {dx là chiều dài 1 bước tiến của bánh xe}
da:=round(dx/r*180/pi);
{da là góc quay của nan hoa tương ứngvới bước tiến dx}
repeat
banhxe(x,y,r,yellow,12,a); {vẽ bánh xe}
delay(40);

banhxe(x,y,r,black,12,a); {vẽ bánh xe với màu nền để xoá}
if (x>=640-r) then x := r; {nếu bánh xe đến mép bên phải thì quay lại bên trái}
x := x + dx;
if a < 0 then a := a + 360;
a := a - da;
{quay ngược chiều dương nên phải trừ}
until keypressed;
END.



27


Đồ họa máy tính - Khoa CNTT - ĐHSPHN

Trong Procedure banhxe(), dx,dy là tọa độ tương đối của đầu nan hoa trong hệ tọa độ
nào ? (gốc tọa độ ở đâu ? trục Oy hướng nào ?)
Trong procedure banhxe, 360 div n là góc gì ? tại sao có dấu trừ trong lệnh dy :=round(r* sin(goc * pi/180)); tọa độ tâm bánh xe ở đâu ?
Tại sao phải gán da:=round(dx/r*180/pi); thay vào đó, nếu gán những giá trị cụ thể như
3,6,9 độ cho góc quay da thì kết quả ra sao ?
Hãy sửa chương trình để bánh xe lăn ngược lại mỗi khi chạm đến 2 biên trái/phải
Hãy dùng kỹ thuật XorPut để xóa bánh xe trong procedure banhxe
Ví dụ: Vẽ bánh xe (2)

uses crt,graph;
var
gd,gm:integer;
r,x,y,direct,buoc:integer; gia_so_goc,goc:real;
procedure ve_banh_xe;

var x1,y1,x2,y2,x3,y3:integer;
begin
x1:=x+round(r*cos(goc));y1:=y-round(r*sin(goc));
x2:=x+round(r*cos(goc+2*pi/3));y2:=y-round(r*sin(goc+2*pi/3));
x3:=x+round(r*cos(goc-2*pi/3));y3:=y-round(r*sin(goc-2*pi/3));
Circle(x,y,r); line(x,y,x1,y1);line(x,y,x2,y2);line(x,y,x3,y3);
delay(30); setcolor(0);
Circle(x,y,r); line(x,y,x1,y1);line(x,y,x2,y2);line(x,y,x3,y3); {xoa}
delay(30);
goc:=goc-gia_so_goc*direct; setcolor(yellow);
end;
begin
direct:=1; buoc:=5;
gd:=detect; initgraph(gd,gm,'c:\tp\bgi');
x:=100; goc:=0;r:=30; y:=200;
gia_so_goc:=buoc/r; setcolor(yellow);
repeat
ve_banh_xe;
if (r> x+direct*buoc) or (x+direct*buoc > getmaxX-r) then direct:=-direct;
x:=(x+direct*buoc);
until Keypressed;
closegraph;


28


×