Chương 2. các thuật toán vẽ đối tượng cơ bản môn Đồ họa máy tính | Trường đại học Kinh Doanh và Công Nghệ Hà Nội

Cung AC từ (0, b), đến C(xT,yT), có độ dốc thuộc [0, -1], x tăng thì ygiảm. Tốc độ biến thiên của x lớn hơn của y (số lượng giá trị nguyên của x nhiều hơn y). Do đó giải thuật sẽ xét và vẽ theo x, còn y sẽ được tính theo x. Cung CB từ (a,0) đến C(xT,yT), có độ dốc thuộc [-1, -], y tăng thì x giảm. Tốc độ biến thiên của y lớn hơn của x (số lượng giá trị nguyên của y nhiều hơn x). Do đó giải thuật sẽ xét và vẽ theo y, còn x sẽ được tính theo y. Tài liệu giúp bạn tham  khảo, ôn tập và đạt kết quả cao. Mời đọc đón xem!

lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Chương 2. CÁC THUẬT TOÁN VẼ ĐỐI
TƯỢNG CƠ BẢN
(tiếp theo)
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 2
s
3. Vẽ ường ellipse
3.1. Phương trình
Tâm hình trùng với tọa ộ gốc (0,0)
x
2
/a
2
+ y
2
/b
2
= 1 y
2
= b
2
- b
2
x
2
/a
2
Giải thuật chỉ cần vẽ cung AB, các phần khác sẽ ược vẽ ối xứng.
Trên cung AB có một iểm C(x
T
, y
T
) mà tại ó tốc ộ biến thiên của X và Y
bằng nhau. Điểm này có ộ dốc bằng -1. Khi ó:
Giải thuật phân chia cung AB thành 2 phần:
- Cung AC từ (0, b), ến C(x
T
,y
T
), có ộ dốc thuộc [0, -1],
x tăng thì y giảm. Tốc biến thiên của x lớn hơn của y (số lượng giá
trị nguyên của x nhiều hơn y). Do ó giải thuật sẽ xét vẽ theo x,
còn y sẽ ược tính theo x.
- Cung CB từ (a,0) ến C(x
T
,y
T
), có ộ dốc thuộc [-1, - ],
y tăng thì x giảm. Tốc biến thiên của y lớn hơn ca x (số lượng giá
trị nguyên của y nhiều hơn x). Do ó giải thuật sẽ xét vẽ theo y,
còn x sẽ ược tính theo y.
3.2. Vẽ ường ellipse theo thuật toán Bresenham
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Giả sử tâm hình trùng với tọa ộ gốc (0,0)
1) Trên cung AC y là iểm
thuộc cung AC
Tại x
i
+
1
ta có:
xi+1 = xi +1
y2 = b2 - b2(xi+1)2/a2 = b2 - b2(xi+1)2/a2 Đặt:
d
1
= y
i
2
- y
2
d
2
= y
2
- (y
i
-1)
2
Tính P
i
:
Pi
= (d
1
- d
2
)a
2
= [y
i
2
+ (y
i
- 1)
2
- 2y
2
]a
2
= [y
i
2
+ (y
i
- 1)
2
- 2(b
2
- b
2
(x
i
+1)
2
/a
2
)]a
2
= y
i
2
a
2
+ (y
i
- 1)
2
a
2
- 2b
2
a
2
+ 2b
2
(x
i
+ 1)
2
- Nếu Pi
< 0 thì y
i
sẽ gần cung AC hơn, ta chọn y
i+1
= y
i
- Nếu Pi
> 0 thì y
i
- 1 sẽ gần cung AC hơn, ta chọn y
i+1
= y
i
- 1 -
Nếu Pi == 0 thì chọn y
i
-1
Tính P
i+1
:
Pi+1 = (yi+1)2a2 + (yi+1 - 1)2a2 - 2b2a2 + 2b2(xi+1 + 1)2
Pi+1 - Pi = (yi+1)2a2 + (yi+1 - 1)2a2 - 2b2a2 + 2b2(xi + 2)2 - [yi2a2 + (yi - 1)2a2 -
2b2a2
y
i
y
d
1
y
i
d
2
Tr
ục y
Cung
tròn
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 4
s
+ 2b
2
(x
i
+ 1)
2
]
Pi
+1
- Pi = a
2
(2(y
i+1
)
2
- 2y
i+1
+1 - 2y
i
2
+ 2y
i
- 1) + 2b
2
(2x
i
+ 3)
Pi+1 = Pi + 2a2((yi+1)2 - yi+1 - yi2 + yi ) + 2b2(2xi + 3)
- Nếu Pi
< 0 thì iểm chọn tiếp theo là (x
i+1
, y
i+1
) = (xi+1, yi):
Pi
+1
= Pi + 2b
2
(2x
i
+ 3)
- Nếu Pi
≥ 0 thì iểm chọn tiếp theo là (x
i+1
, y
i+1
) = (x
i
+1, y
i
-1)
Pi+1 = Pi + 2a2((yi -1) 2 - yi + 1 - yi2 + yi ) + 2b2(2xi + 3)
Pi
+1
= Pi + 2b
2
(2x
i
+ 3) + 4a
2
(1 - y
i
)
Tính P
1
cho iểm bắt ầu (0, b)
P1 = y12a2 + (y1 - 1)2a2 - 2b2a2 + 2b2(x1 + 1)2
= b
2
a
2
+ (b - 1)
2
a
2
- 2a
2
b
2
+ 2b
2
= b
2
a
2
+ a
2
b
2
- 2a
2
b + a
2
- 2a
2
b
2
+ 2b
2
= -2a
2
b + a
2
+ 2b
2
= a
2
(1 - 2b) + 2b
2
Giải thuật p = a
2
(1 - 2b) +
2b
2
; //Tính P
1
x = 0; y = b;
Vẽ iểm ảnh (x, y);
B1: Nếu x < x
T
thì chuyển sang bước 2, ngược lại thì dừng
B2: //Tính iểm tiếp theo
Nếu p<0 thì //iểm kế là (x
i
+1, y
i
)
p = p + 2b
2
(2x + 3); //Tính p
i+1
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Ngược lại: //iểm kế là (x
i
+1, y
i
-1)
p = p + 2b
2
(2x + 3) + 4a
2
(1 y); //Tính p
i+1
y--;
B3: x++;
B4: Vẽ iểm ảnh (x, y); Quay lại B1.
2) Trên cung CB
Giải thuật trên cung CB tương tự trên cung AC. Tuy nhiên ta cần sự thay
ổi vai trò của x với y và a với b. Cung CB i từ (a, 0) ến (x
T
, y
T
) ược xét vẽ theo
y, còn x sẽ ược tính theo y.
3) Chương trình
#include <GL/glut.h>
#include <math.h>
GLint Xc = 20, Yc = 20, A = 200, B = 150;
void drawPoints(int x, int y, int xc, int yc)
{ glVertex2i(xc + x, yc +
y); glVertex2i(xc - x, yc +
y); glVertex2i(xc + x, yc -
y); glVertex2i(xc - x, yc -
y);
} void drawEllipseBresenham(GLint xc, GLint yc, GLint a, GLint
b)
{ float a2 = a*a; float b2 = b*b;
int x = 0; int y = b; float xt = a *
a / sqrt(a * a + b * b); float yt = b *
b / sqrt(a * a + b * b); float p =
a2*(1 - 2*b) + 2*b2;
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 6
s
glBegin(GL_POINTS);
drawPoints(x, y, yc, yc); //vẽ phần
1 (cung AC) //while (b2 * x < y *
a2)//ok while (x < xt) { if (p <
0) p += b2 * (4 * x + 6);
else { p += b2 * (4 * x + 6) +
4 * a2 * (1 - y); y--; }
x++; drawPoints(x, y, yc, yc);
}
//vẽ phần 2 (cung CB) y = 0; x = a;
drawPoints(x, y, yc, yc); p = b2*(1 - 2*a) +
2*a2; //while (a2 * y < x * b2)//ok while
(y <= yt) { if (p < 0) p += a2 * (4
* y + 6); else { p += a2 * (4 * y +
6) + 4 * b2 * (1 - x); x--; }
y++; drawPoints(x, y, yc, yc);
}
glEnd();
} void display() {
drawEllipseBresenham(Xc, Yc, A, B);
glFlush();
} int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("My App!");
glutDisplayFunc(display); gluOrtho2D(-
250.0, 250.0, -250.0, 250.0);
glutMainLoop();
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
}
Nhận xét 1: x
2
/a
2
+ y
2
/b
2
= 1 b2x2 + a2y2 = a2b2
2xb
2
dx + 2ya
2
dy = 0
dy/dx = - 2xb
2
/2ya
2
Tại dốc dy/dx = -1: -
1 = - 2xb
2
/2ya
2
ya
2
=
xb
2
Do ó ta có thể sử dụng iều kiện xb
2
<=ya
2
trên cung AC, hoặc ya
2
<=xb
2
trên cung CB. Từ ó cải tiến cách viết chương trình.
Nhận xét 2: Khi vẽ cung CB, nếu ta sử dụng iều kiện y < yt hoặc 2 *
b
2
* x > 2 * a
2
* y thì sẽ có vài iểm ảnh ược vẽ lại lần 2 gần y
T
. Do ó ta có thể sử
dụng iều kiện y < Y, với Y là iểm ảnh kế tiếp iểm ảnh cuối cùng của cung AC.
Nhận xét 3: Trên cung CB ta i từ (a, 0) ến (x
T
, y
T
), xét và vẽ theo y, n x
sẽ ược tính theo y. Tuy nhiên ta có thể i từ sau iểm vẽ cuối cùng của cung AC ến
(a,0).
3.3. Vẽ ường ellipse theo thuật toán trung iểm
x
2
/a
2
+ y
2
/b
2
= 1 x
2
.b
2
+ y
2
.a
2
= a
2
.b
2
x
2
.b
2
+
y
2
.a
2
- a
2
.b
2
= 0
d = x
2
.b
2
+ y
2
.a
2
- a
2
.b
2
- Nếu d == 0, thì (x,y) thuộc ường ellipse.
- Nếu d > 0, thì (x,y) ở ngoài ường ellipse.
- Nếu d < 0, thì (x,y) ở trong ường ellipse.
Ta tính d
1
, d
i
, d
i+1
tương tự thuật toán midpoint vẽ ường tròn.
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 8
s
1) Trên cung AC
d
1
= b
2
- a
2
b + a
2
/4 = b
2
- a
2
(b 1/4)
Nhận xét: Do b lớn hơn rất nhiều so với ¼ nên có thể tính d
1
= b
2
- a
2
b
d
i
= b
2
(x
i
+ 1)
2
+ a
2
(y
i
1/2)
2
a
2
b
2
Nếu d
i
< 0 thì y
i+1
= y
i
(chọn A) và d
i+1
= d
i
+ b
2
(3 + 2x
i
)
Nếu d
i
>= 0 thì y
i+1
= y
i
- 1 (chọn B) và d
i+1
= d
i
+ b
2
(3 + 2x
i
) + a
2
(2 - 2y
i
)
Giải thuật d = b2 - a
2
b +
0.25a
2
; //Tính d
1
x = 0; y = b;
Vẽ iểm ảnh (x, y);
B1: Nếu x < x
T
thì chuyển sang bước 2, ngược lại thì dừng
B2: //Tính iểm tiếp theo
Nếu d<0 thì //iểm kế là (x
i
+1, y
i
)
d = d + 3b
2
+ 2b
2
x; //Tính d
i+1
Ngược lại: //iểm kế là (x
i
+1, y
i
-1)
d = d + 3b
2
+ 2b
2
x + 2a
2
- 2a
2
y; //Tính d
i+1
y-
-;
B3: x++;
B4: Vẽ iểm ảnh (x, y); Quay lại B1.
y
i
M
y
i
2
/
A
y
B
y
i
y
i
y
M
A
y
i
/
2
y
i
-1
B
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
2) Trên cung CB
Giải thuật trên cung CB tương tự trên cung AC. Tuy nhiên ta cần sự thay
ổi vai trò của x với y cũng như a với b. Cung CB i từ (a, 0) ến (xT, yT) ược xét
và vẽ theo y, còn x sẽ ược tính theo y.
3) Chương trình
#include <GL/glut.h>
#include <math.h>
GLint Xc = 0, Yc = 0, A = 150, B = 100;
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 10
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
#define Round(a) ((long)(a+0.5)) void
drawPoints(int x, int y, int xc, int yc)
{ glVertex2i(xc + x, yc +
y); glVertex2i(xc - x, yc +
y); glVertex2i(xc + x, yc -
y); glVertex2i(xc - x, yc -
y);
} void drawEllipseMidpoint(GLint xc, GLint yc, GLint a, GLint
b)
{ long x, y, fx, fy, a2, b2, p;
x = 0; y = b; a2 = a * a;
b2 = b * b; float xt = a2 /
sqrt(a2 + b2); float yt = b2 /
sqrt(a2 + b2);
glBegin(GL_POINTS);
drawPoints(x, y, xc, yc); //p = (b2 - a2 * b +
0.25 * a2); //p = Round(b2 - a2 * b + 0.25 * a2);
//ok p = b2 - b * a2; while (2 * b2 * x < 2 * a2
* y) { //hoặc x < xt if(p < 0) p +=
3*b2 + 2 * b2 * x ; else { p += 3*b2
+ 2 * b2 * x -2 * a2 * y + 2*a2; y--; }
x++; drawPoints(x, y, xc, yc); }
GLint Y = y-1; //Y là iểm kế tiếp iểm cuối cùng của cung AC
x = a; y = 0; drawPoints(x, y, xc, yc); //p = a2 - b2 * a +
0.25 * b2;
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Downloaded by ANhh Trân
(Anhhtrann14062003@gmail.com)
Trang
11
//p = Round(a2 - b2 * a + 0.25 * b2); //ok p = a2 -
a*b2; while (y < Y) {// 2 * b2 * x > 2 * a2 * y //Hoặc
y < yt if(p < 0) p += 3*a2 + 2 * a2 * y;
else { p += 3 * a2 + 2 * a2 * y - 2 * b2 * x
+2*b2; x--; } y++; drawPoints(x,
y, xc, yc);
} glEnd(); } void display() {
drawEllipseBresenham(Xc, Yc, A, B);
glColor3f(1, 0, 0);
drawEllipseMidpoint(Xc, Yc, A, B);
glFlush();
} int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("My App!");
glutDisplayFunc(display); gluOrtho2D(-
250.0, 250.0, -250.0, 250.0);
glutMainLoop();
}
4. Xử lý sự kiện phím
4.1. Bắt sự kiện nhấn phím thường
Hàm xử lý sự kiện:
void tênhàm(unsigned char key, int x, int y)
- key cho biết phím ược nhấn. Giá trị của nó là
hằng ký tự ‘A’, ‘B’,….
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 12
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
hoặc mã ASCII của phím nhấn.
- x, y cho biết vị trí hiện hành trong cửa sổ vẽ
Lưu ý: Tên hàm là tự ặt.
Trong hàm main, ăng ký hàm xử lý sự kiện:
glutKeyboardFunc(tênhàm);
Ta phải ăng ký hàm thì hàm mới hoạt ộng khi có sự kiện phím xảy ra.
dụ: Chương trình vẽ hình chữ nhựt nền màu trắng. Nhấn phím b sẽ vẽ
ường chữ nhựt màu trắng, nhấn phím a sẽ vhình chữ nhựt nền màu trắng. Khi
chạy thử nên nhấn b trước.
#include <GL/glut.h>
#include <stdlib.h> //sử dụng lệnh exit unsigned char pressedkey = 'a';
//Nếu là a thì tô lại nền, Nếu là b thì vẽ lại ường
void OnKeyDown(unsigned char key, int x, int y)
{ pressedkey = key; if (key == 27)
//phím Esc ược nhấn exit(-1);
//Thoát chương trình else
glutPostRedisplay();
} void
display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (pressedkey == 'a' || pressedkey == 'A') { //chỉ ịnh thiết lập màu nền
vẽ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3f(0.0f, 1.0f, 0.0f); //nếu không có lệnh này sẽ lấy màu mặc
ịnh
}
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Downloaded by ANhh Trân
(Anhhtrann14062003@gmail.com)
Trang
13
else if (pressedkey == 'b' || pressedkey == 'B') { //chỉ ịnh thiết lập màu
ường vẽ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0f, 0.0f, 0.0f); //nếu không có lệnh này sẽ lấy màu mặc
ịnh
}
glBegin(GL_POLYGON);
glVertex2i(25, 25);
glVertex2i(75, 25);
glVertex2i(75, 75);
glVertex2i(25, 75);
glEnd(); glFlush();
} int main(int argc, char* argv[]) { glutInit(&argc, argv);
glutInitWindowSize(500, 500); glutCreateWindow("My App!");
glutDisplayFunc(display); glutKeyboardFunc(OnKeyDown); //Đăng ký
hàm xử lý sự kiện phím
thường gluOrtho2D(-250.0, 250.0, -250.0,
250.0); glutMainLoop();
}
glutPostRedisplay(): Khi sự kiện xảy ra, thực hiện lại hàm hiển thị.
Hàm hiển thị là hàm tên là display ược ăng ký bởi lệnh
glutDisplayFunc(display).
Hàm xsự kiện ặt biến pressedkey bằng phím ược nhấn. sẽ thoát
chương trình khi người dùng nhấn phím ESC. Ngược lại, nó gọi thực hiện lại hàm
display bằng lệnh glutPostRedisplay. Hàm display dựa vào giá trị của biến
pressedkey ể quyết ịnh làm.
4.2. Bắt sự kiện nhấn phím chức năng
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 14
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
Các phím chức năng ược bắt bởi sự kiện:
- F1 ến F12
- Up, Down, Left, Right
- Home, Insert, End, Page Down, Page Up Các hằng ứng với các phím
chức năng:
GLUT_KEY_F1, …. GLUT_KEY_F12
GLUT_KEY_LEFT phím qua trái
GLUT_KEY_RIGHT phím qua phải GLUT_KEY_UP phím
i lên
GLUT_KEY_DOWN phím i xuống
GLUT_KEY_PAGE_UP phím Page Up
GLUT_KEY_PAGE_DOWN phím Page Down
GLUT_KEY_HOME phím Home
GLUT_KEY_END phím End
GLUT_KEY_INSERT phím Insert
Hàm xử lý sự kiện:
void tênhàm(int key, int x, int y)
- key cho biết phím nào ược nhấn - x, y cho
biết vị trí hiện hành trong cửa sổ vẽ Trong hàm
main, ăng ký hàm xử lý sự kiện:
glutSpecialFunc(tênhàm);
4.3. Bắt sự kiện nhả phím
Hàm xử lý sự kiện:
void tênhàm(int key, int x, int y) void
tênhàm(unsigned char key, int x, int y); Đăng
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Downloaded by ANhh Trân
(Anhhtrann14062003@gmail.com)
Trang
15
ký hàm xử lý sự kiện:
glutSpecialUpFunc(tênhàm);
glutKeyboardUpFunc(tênhàm);
5. Xử lý sự kiện chuột
5.1. Bắt sự kiện nhấp chuột
Hàm xử lý sự kiện nhấp chuột:
void tênhàm(int button, int state, int x, int y) -
button cho biết nút chuột nào ược nhấp.
- state cho biết trạng thái nhấn hay nhả ra
(GLUT_DOWN hay GLUT_UP)
- x, y cho biết vị trí hiện hành của chut trong cửa s vẽ
Các hằng ứng với các nút chuột:
GLUT_LEFT_BUTTON
GLUT_MIDDLE_BUTTON
GLUT_RIGHT_BUTTON
Trong hàm main, ăng ký hàm xử lý sự kiện:
glutMouseFunc(tênhàm);
Cấu trúc tổng quát của hàm xử lý sự kiện nhấp chuột:
void tênhàm(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_UP) {
//code
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 16
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
}
else {
//code }
}
else if(button == GLUT_RIGHT_BUTTON) {
if (state == GLUT_UP) {
//code
}
else {
//code
}
}
else if(button == GLUT_MIDDLE_BUTTON) {
//code
}
}
dụ: Khi nhấp nút trái chuột sẽ hiển thị ường vẽ, khi nhả nút shiển thị
nền vẽ. Khi nhấp nút phảii chuột sẽ hiển thị ường vẽ, khi nhả nút sẽ hiển thị nền
vẽ.
#include <GL/glut.h> GLint flag = 1; void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_UP) { flag = 1;
glutPostRedisplay();
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Downloaded by ANhh Trân
(Anhhtrann14062003@gmail.com)
Trang
17
}
else {
flag = 2;
glutPostRe
display();
}
}
else if (button == GLUT_RIGHT_BUTTON) {
if (state == GLUT_UP) { flag = 3;
glutPostRedisplay();
} else {
flag = 4;
glutPostRedisplay();
}
}
} void
display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (flag == 1) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3f(0.0f, 1.0f, 0.0f);
} else if (flag ==
2) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0f, 0.0f, 0.0f);
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 18
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
} else if (flag ==
3) {
glPolygonMode(GL_
FRONT_AND_BAC
K, GL_FILL);
glColor3f(0.0f, 0.0f,
1.0f);
} else if (flag ==
4) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0f, 0.0f, 0.0f);
}
glBegin(GL_POLYGON);
glVertex2i(25, 25);
glVertex2i(75, 25);
glVertex2i(75, 75);
glVertex2i(25, 75);
glEnd(); glFlush();
} int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(500, 500);
glutCreateWindow("My App!");
glutDisplayFunc(display);
glutMouseFunc(mouse); gluOrtho2D(-
250.0, 250.0, -250.0, 250.0);
glutMainLoop();
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Downloaded by ANhh Trân
(Anhhtrann14062003@gmail.com)
Trang
19
}
Lưu ý: Nếu không quan tâm trạng thái nhấn hay nhả nút, mà chỉ quan tâm
nút nào nhấn thì ta xét như sau if (button == GLUT_LEFT_BUTTON) {
flag = 1;
glutPostRedisplay();
}
else if (button == GLUT_RIGHT_BUTTON) {
flag = 2; glutPostRedisplay(); }
5.2. Vị trí nhấp chuột
Trong các hàm xử lý sự kiện, x, y là vị trí hiện hành trong cửa sổ vẽ,
không phải là tọa ộ vẽ trên hệ tọa ộ vẽ. Ta có thể cũng muốn vẽ theo vị trí nhấp
chuột. Do các hàm vẽ sử dụng tọa ộ vẽ, nên ta cần biết vị trí nhấp chuột hiện
hành trên
Công thức chuyển ổi từ vị trí (x,y) trên cửa sổ vẽ sang tọa ộ vẽ (x’, y’) là:
y' = ((bottom - top) / winHeight) * y + top;
x’ = ((right - left) / winWidth) * x + left;
Ví dụ: Vẽ các oạn thằng từ v trí nhấp chuột thứ 0 ến thứ 1, thứ 1 ến thứ
2,…, thứ 18 ến thứ 19.
cửa sổ vẽ sẽ có tọa ộ vẽ tương ứng là bao nhiêu.
glutInitWindowSize(winWidth, winHeight) gluOrtho2D(left, right, bottom, top)
top
bottom
left
right
lOMoARcPSD| 48704538
ĐỒ HỌA MÁY TÍNH
GV: Hồ Ngọc Thanh
Trang 20
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)
#include <GL/glut.h>
//NUM là số lần tối a nhấp chuột
#define NUM 20
//cấu trúc lưu mỗi iểm (vị trí) nhấp chuột.
struct Point { int x, y; };
//Mảng lưu các iểm nhấp chuột
Point points[NUM];
//biến lưu thứ tự cuối của iểm nhấp chuột, iểm ầu tiên có thứ tự 0 int
last = -1; //thứ tự -1 là chưa có iểm nhấp chuột
//GLfloat winWidth = glutGet(GLUT_SCREEN_WIDTH);
//GLfloat winHeight = glutGet(GLUT_SCREEN_HEIGHT);
GLfloat winWidth = 500;
GLfloat winHeight = 500;
GLfloat bottom = -winHeight/2, top = winHeight/2, left = -winWidth/2,
right = winWidth/2;
//GLfloat bottom = 0, top = winHeight, left = 0, right = winWidth; void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && last < NUM - 1) {
++last; //thứ tự của iểm nhấp chuột points[last].y
= ((bottom - top) / winHeight) * y + top; points[last].x
= ((right - left) / winWidth) * x + left;
} else last = -1; //với giá trị này sẽ không
vẽ, tức là xóa glutPostRedisplay();
} void
display()
| 1/25

Preview text:

lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Chương 2. CÁC THUẬT TOÁN VẼ ĐỐI TƯỢNG CƠ BẢN (tiếp theo) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
3. Vẽ ường ellipse 3.1. Phương trình
Tâm hình trùng với tọa ộ gốc (0,0)
x2/a2 + y2/b2 = 1 y2 = b2 - b2x2/a2
Giải thuật chỉ cần vẽ cung AB, các phần khác sẽ ược vẽ ối xứng.
Trên cung AB có một iểm C(x
) mà tại ó tốc ộ biến thiên của X và Y T, yT
bằng nhau. Điểm này có ộ dốc bằng -1. Khi ó:
Giải thuật phân chia cung AB thành 2 phần: -
Cung AC từ (0, b), ến C(xT,yT), có ộ dốc thuộc [0, -1],
x tăng thì y giảm. Tốc ộ biến thiên của x lớn hơn của y (số lượng giá
trị nguyên của x nhiều hơn y). Do ó giải thuật sẽ xét và vẽ theo x,
còn y sẽ ược tính theo x. -
Cung CB từ (a,0) ến C(xT,yT), có ộ dốc thuộc [-1, - ],
y tăng thì x giảm. Tốc ộ biến thiên của y lớn hơn của x (số lượng giá
trị nguyên của y nhiều hơn x). Do ó giải thuật sẽ xét và vẽ theo y,
còn x sẽ ược tính theo y.
3.2. Vẽ ường ellipse theo thuật toán Bresenham Trang 2 s lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Giả sử tâm hình trùng với tọa ộ gốc (0,0)
1) Trên cung AC y là iểm thuộc cung AC y i d 1 y y d 2 Cung i -1 tròn Tr ục y Tại xi+1 ta có: xi+1 = xi +1
y2 = b2 - b2(xi+1)2/a2 = b2 - b2(xi+1)2/a2 Đặt: d 2 1 = yi - y2 d2 = y2 - (yi -1)2  Tính Pi : P = 2 i
(d1 - d2)a2 = [yi + (yi - 1)2 - 2y2]a2 = [y 2
i + (yi - 1)2 - 2(b2 - b2(xi+1)2/a2)]a2 = y 2
i a2 + (yi - 1)2a2 - 2b2a2 + 2b2(xi + 1)2
- Nếu Pi < 0 thì yi sẽ gần cung AC hơn, ta chọn yi+1 = yi
- Nếu Pi > 0 thì yi - 1 sẽ gần cung AC hơn, ta chọn yi+1 = yi - 1 -
Nếu Pi == 0 thì chọn yi -1  Tính Pi+1 :
Pi+1 = (yi+1)2a2 + (yi+1 - 1)2a2 - 2b2a2 + 2b2(xi+1 + 1)2
Pi+1 - Pi = (yi+1)2a2 + (yi+1 - 1)2a2 - 2b2a2 + 2b2(xi + 2)2 - [yi2a2 + (yi - 1)2a2 - 2b2a2 lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh + 2b2(xi + 1)2] P 2
i+1 - Pi = a2(2(yi+1)2 - 2yi+1 +1 - 2yi + 2yi - 1) + 2b2(2xi + 3)
Pi+1 = Pi + 2a2((yi+1)2 - yi+1 - yi2 + yi ) + 2b2(2xi + 3)
- Nếu Pi < 0 thì iểm chọn tiếp theo là (x i+1, yi+1) = (xi+1, yi): Pi+1 = Pi + 2b2(2xi + 3)
- Nếu Pi ≥ 0 thì iểm chọn tiếp theo là (x i+1, yi+1) = (xi +1, yi -1)
Pi+1 = Pi + 2a2((yi -1) 2 - yi + 1 - yi2 + yi ) + 2b2(2xi + 3)
Pi+1 = Pi + 2b2(2xi + 3) + 4a2(1 - yi )
 Tính P cho iểm bắt ầu (0, b) 1
P1 = y12a2 + (y1 - 1)2a2 - 2b2a2 + 2b2(x1 + 1)2
= b2a2 + (b - 1)2a2 - 2a2b2 + 2b2
= b2a2 + a2b2 - 2a2b + a2 - 2a2b2 + 2b2 = -2a2b + a2 + 2b2 = a2(1 - 2b) + 2b2
Giải thuật p = a2(1 - 2b) +
2b2 ; //Tính P1 x = 0; y = b; Vẽ iểm ảnh (x, y);
B1: Nếu x < xT thì chuyển sang bước 2, ngược lại thì dừng
B2: //Tính iểm tiếp theo
Nếu p<0 thì //iểm kế là (xi+1, yi)
p = p + 2b2(2x + 3); //Tính pi+1 Trang 4 s lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Ngược lại: //iểm kế là (xi+1, yi -1)
p = p + 2b2(2x + 3) + 4a2(1 – y); //Tính pi+1 y--; B3: x++;
B4: Vẽ iểm ảnh (x, y); Quay lại B1. 2) Trên cung CB
Giải thuật trên cung CB tương tự trên cung AC. Tuy nhiên ta cần có sự thay
ổi vai trò của x với y và a với b. Cung CB i từ (a, 0) ến (x ) ược xét và vẽ theo T, yT
y, còn x sẽ ược tính theo y. 3) Chương trình #include #include
GLint Xc = 20, Yc = 20, A = 200, B = 150;
void drawPoints(int x, int y, int xc, int yc) { glVertex2i(xc + x, yc + y); glVertex2i(xc - x, yc + y); glVertex2i(xc + x, yc - y); glVertex2i(xc - x, yc - y);
} void drawEllipseBresenham(GLint xc, GLint yc, GLint a, GLint b)
{ float a2 = a*a; float b2 = b*b;
int x = 0; int y = b; float xt = a *
a / sqrt(a * a + b * b); float yt = b *
b / sqrt(a * a + b * b); float p = a2*(1 - 2*b) + 2*b2; lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh glBegin(GL_POINTS);
drawPoints(x, y, yc, yc); //vẽ phần
1 (cung AC) //while (b2 * x < y *
a2)//ok while (x < xt) { if (p < 0) p += b2 * (4 * x + 6);
else { p += b2 * (4 * x + 6) + 4 * a2 * (1 - y); y--; }
x++; drawPoints(x, y, yc, yc); }
//vẽ phần 2 (cung CB) y = 0; x = a;
drawPoints(x, y, yc, yc); p = b2*(1 - 2*a) +
2*a2; //while (a2 * y < x * b2)//ok while
(y <= yt) { if (p < 0) p += a2 * (4
* y + 6); else { p += a2 * (4 * y + 6) + 4 * b2 * (1 - x); x--; }
y++; drawPoints(x, y, yc, yc); } glEnd(); } void display() {
drawEllipseBresenham(Xc, Yc, A, B); glFlush();
} int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); glutCreateWindow("My App!");
glutDisplayFunc(display); gluOrtho2D(- 250.0, 250.0, -250.0, 250.0); glutMainLoop(); Trang 6 s lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh }
Nhận xét 1: x2/a2 + y2/b2 = 1 b2x2 + a2y2 = a2b2 2xb2dx + 2ya2dy = 0 dy/dx = - 2xb2 /2ya2 Tại ộ dốc dy/dx = -1: - 1 = - 2xb2 /2ya2 ya2 = xb2
Do ó ta có thể sử dụng iều kiện xb2<=ya2 trên cung AC, hoặc ya2<=xb2
trên cung CB. Từ ó cải tiến cách viết chương trình. 
Nhận xét 2: Khi vẽ cung CB, nếu ta sử dụng iều kiện y < yt hoặc 2 *
b2 * x > 2 * a2 * y thì sẽ có vài iểm ảnh ược vẽ lại lần 2 gần y . Do ó ta có thể sử T
dụng iều kiện y < Y, với Y là iểm ảnh kế tiếp iểm ảnh cuối cùng của cung AC. 
Nhận xét 3: Trên cung CB ta i từ (a, 0) ến (xT, yT), xét và vẽ theo y, còn x
sẽ ược tính theo y. Tuy nhiên ta có thể i từ sau iểm vẽ cuối cùng của cung AC ến (a,0).
3.3. Vẽ ường ellipse theo thuật toán trung iểm x2/a2 + y2/b2 = 1 x2.b2 + y2.a2 = a2.b2 x2.b2 + y2.a2 - a2.b2 = 0  d = x2.b2 + y2.a2 - a2.b2
- Nếu d == 0, thì (x,y) thuộc ường ellipse.
- Nếu d > 0, thì (x,y) ở ngoài ường ellipse.
- Nếu d < 0, thì (x,y) ở trong ường ellipse. Ta tính d
tương tự thuật toán midpoint vẽ ường tròn. 1, di, di+1 lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh 1) Trên cung AC y i y A A
i y y i- / 1 2 y M
i-1 / 2 M y y i-1 B
y i-1 B
d1 = b2 - a2b + a2/4 = b2 - a2(b – 1/4)
Nhận xét: Do b lớn hơn rất nhiều so với ¼ nên có thể tính d1 = b2 - a2b
di = b2(xi + 1)2 + a2(yi – 1/2)2 – a2b2
Nếu di < 0 thì yi+1 = yi (chọn A) và di+1 = di + b2(3 + 2xi )
Nếu di >= 0 thì yi+1 = yi - 1 (chọn B) và di+1 = d + b2(3 + 2x i i ) + a2(2 - 2yi )
Giải thuật d = b2 - a2b +
0.25a2; //Tính d1 x = 0; y = b; Vẽ iểm ảnh (x, y);
B1: Nếu x < xT thì chuyển sang bước 2, ngược lại thì dừng
B2: //Tính iểm tiếp theo
Nếu d<0 thì //iểm kế là (xi+1, yi)
d = d + 3b2 + 2b2x; //Tính di+1
Ngược lại: //iểm kế là (xi+1, yi -1)
d = d + 3b2 + 2b2x + 2a2 - 2a2y; //Tính di+1 y- -; B3: x++;
B4: Vẽ iểm ảnh (x, y); Quay lại B1. Trang 8 s lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh 2) Trên cung CB
Giải thuật trên cung CB tương tự trên cung AC. Tuy nhiên ta cần có sự thay
ổi vai trò của x với y cũng như a với b. Cung CB i từ (a, 0) ến (xT, yT) ược xét
và vẽ theo y, còn x sẽ ược tính theo y. 3) Chương trình #include #include
GLint Xc = 0, Yc = 0, A = 150, B = 100; lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
#define Round(a) ((long)(a+0.5)) void
drawPoints(int x, int y, int xc, int yc) { glVertex2i(xc + x, yc + y); glVertex2i(xc - x, yc + y); glVertex2i(xc + x, yc - y); glVertex2i(xc - x, yc - y);
} void drawEllipseMidpoint(GLint xc, GLint yc, GLint a, GLint b)
{ long x, y, fx, fy, a2, b2, p; x = 0; y = b; a2 = a * a; b2 = b * b; float xt = a2 /
sqrt(a2 + b2); float yt = b2 / sqrt(a2 + b2); glBegin(GL_POINTS);
drawPoints(x, y, xc, yc); //p = (b2 - a2 * b +
0.25 * a2); //p = Round(b2 - a2 * b + 0.25 * a2);
//ok p = b2 - b * a2; while (2 * b2 * x < 2 * a2
* y) { //hoặc x < xt if(p < 0) p +=
3*b2 + 2 * b2 * x ; else { p += 3*b2
+ 2 * b2 * x -2 * a2 * y + 2*a2; y--; }
x++; drawPoints(x, y, xc, yc); }
GLint Y = y-1; //Y là iểm kế tiếp iểm cuối cùng của cung AC
x = a; y = 0; drawPoints(x, y, xc, yc); //p = a2 - b2 * a + 0.25 * b2; Trang 10
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
//p = Round(a2 - b2 * a + 0.25 * b2); //ok p = a2 -
a*b2; while (y < Y) {// 2 * b2 * x > 2 * a2 * y //Hoặc
y < yt if(p < 0) p += 3*a2 + 2 * a2 * y;
else { p += 3 * a2 + 2 * a2 * y - 2 * b2 * x
+2*b2; x--; } y++; drawPoints(x, y, xc, yc);
} glEnd(); } void display() {
drawEllipseBresenham(Xc, Yc, A, B); glColor3f(1, 0, 0);
drawEllipseMidpoint(Xc, Yc, A, B); glFlush();
} int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); glutCreateWindow("My App!");
glutDisplayFunc(display); gluOrtho2D(- 250.0, 250.0, -250.0, 250.0); glutMainLoop(); }
4. Xử lý sự kiện phím
4.1. Bắt sự kiện nhấn phím thường Hàm xử lý sự kiện:
void tênhàm(unsigned char key, int x, int y)
- key cho biết phím ược nhấn. Giá trị của nó là
hằng ký tự ‘A’, ‘B’,…. Trang 11 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
hoặc mã ASCII của phím nhấn.
- x, y cho biết vị trí hiện hành trong cửa sổ vẽ
Lưu ý: Tên hàm là tự ặt.
Trong hàm main, ăng ký hàm xử lý sự kiện:
glutKeyboardFunc(tênhàm);
Ta phải ăng ký hàm thì hàm mới hoạt ộng khi có sự kiện phím xảy ra.
Ví dụ: Chương trình vẽ hình chữ nhựt nền màu trắng. Nhấn phím b sẽ vẽ
ường chữ nhựt màu trắng, nhấn phím a sẽ vẽ hình chữ nhựt nền màu trắng. Khi
chạy thử nên nhấn b trước
. #include
#include //sử dụng lệnh exit unsigned char pressedkey = 'a';
//Nếu là a thì tô lại nền, Nếu là b thì vẽ lại ường
void OnKeyDown(unsigned char key, int x, int y)
{ pressedkey = key; if (key == 27)
//phím Esc ược nhấn exit(-1); //Thoát chương trình else glutPostRedisplay(); } void display() {
glClear(GL_COLOR_BUFFER_BIT);
if (pressedkey == 'a' || pressedkey == 'A') { //chỉ ịnh thiết lập màu nền
vẽ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3f(0.0f, 1.0f, 0.0f); //nếu không có lệnh này sẽ lấy màu mặc ịnh } Trang 12
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
else if (pressedkey == 'b' || pressedkey == 'B') { //chỉ ịnh thiết lập màu
ường vẽ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0f, 0.0f, 0.0f); //nếu không có lệnh này sẽ lấy màu mặc ịnh } glBegin(GL_POLYGON); glVertex2i(25, 25); glVertex2i(75, 25); glVertex2i(75, 75); glVertex2i(25, 75); glEnd(); glFlush();
} int main(int argc, char* argv[]) { glutInit(&argc, argv);
glutInitWindowSize(500, 500); glutCreateWindow("My App!");
glutDisplayFunc(display); glutKeyboardFunc(OnKeyDown); //Đăng ký
hàm xử lý sự kiện phím
thường gluOrtho2D(-250.0, 250.0, -250.0, 250.0); glutMainLoop(); }
glutPostRedisplay(): Khi sự kiện xảy ra, thực hiện lại hàm hiển thị.
Hàm hiển thị là hàm tên là display ược ăng ký bởi lệnh glutDisplayFunc(display).
Hàm xử lý sự kiện ặt biến pressedkey bằng phím ược nhấn. Nó sẽ thoát
chương trình khi người dùng nhấn phím ESC. Ngược lại, nó gọi thực hiện lại hàm
display bằng lệnh glutPostRedisplay. Hàm display dựa vào giá trị của biến
pressedkey ể quyết ịnh làm gì.
4.2. Bắt sự kiện nhấn phím chức năng Trang 13 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
Các phím chức năng ược bắt bởi sự kiện: - F1 ến F12 - Up, Down, Left, Right
- Home, Insert, End, Page Down, Page Up Các hằng ứng với các phím chức năng:
GLUT_KEY_F1, …. GLUT_KEY_F12 GLUT_KEY_LEFT phím qua trái
GLUT_KEY_RIGHT phím qua phải GLUT_KEY_UP phím i lên GLUT_KEY_DOWN phím i xuống GLUT_KEY_PAGE_UP phím Page Up
GLUT_KEY_PAGE_DOWN phím Page Down GLUT_KEY_HOME phím Home GLUT_KEY_END phím End GLUT_KEY_INSERT phím Insert Hàm xử lý sự kiện:
void tênhàm(int key, int x, int y)
- key cho biết phím nào ược nhấn - x, y cho
biết vị trí hiện hành trong cửa sổ vẽ Trong hàm
main, ăng ký hàm xử lý sự kiện:
glutSpecialFunc(tênhàm);
4.3. Bắt sự kiện nhả phím Hàm xử lý sự kiện:
void tênhàm(int key, int x, int y) void
tênhàm(unsigned char key, int x, int y); Đăng Trang 14
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh
ký hàm xử lý sự kiện: glutSpecialUpFunc(tênhàm); glutKeyboardUpFunc(tênhàm);
5. Xử lý sự kiện chuột
5.1. Bắt sự kiện nhấp chuột
Hàm xử lý sự kiện nhấp chuột:
void tênhàm(int button, int state, int x, int y) -
button cho biết nút chuột nào ược nhấp. -
state cho biết trạng thái nhấn hay nhả ra (GLUT_DOWN hay GLUT_UP) -
x, y cho biết vị trí hiện hành của chuột trong cửa sổ vẽ
Các hằng ứng với các nút chuột: GLUT_LEFT_BUTTON GLUT_MIDDLE_BUTTON GLUT_RIGHT_BUTTON
Trong hàm main, ăng ký hàm xử lý sự kiện: glutMouseFunc(tênhàm);
Cấu trúc tổng quát của hàm xử lý sự kiện nhấp chuột:
void tênhàm(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_UP) { //code Trang 15 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh } else { //code } }
else if(button == GLUT_RIGHT_BUTTON) { if (state == GLUT_UP) { //code } else { //code } }
else if(button == GLUT_MIDDLE_BUTTON) { //code } }
Ví dụ: Khi nhấp nút trái chuột sẽ hiển thị ường vẽ, khi nhả nút sẽ hiển thị
nền vẽ. Khi nhấp nút phảii chuột sẽ hiển thị ường vẽ, khi nhả nút sẽ hiển thị nền vẽ. #include GLint flag = 1; void
mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_UP) { flag = 1; glutPostRedisplay(); Trang 16
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh } else { flag = 2; glutPostRe display(); } }
else if (button == GLUT_RIGHT_BUTTON) {
if (state == GLUT_UP) { flag = 3; glutPostRedisplay(); } else { flag = 4; glutPostRedisplay(); } } } void display() {
glClear(GL_COLOR_BUFFER_BIT); if (flag == 1) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glColor3f(0.0f, 1.0f, 0.0f); } else if (flag == 2) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(1.0f, 0.0f, 0.0f); Trang 17 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh } else if (flag == 3) { glPolygonMode(GL_ FRONT_AND_BAC K, GL_FILL); glColor3f(0.0f, 0.0f, 1.0f); } else if (flag == 4) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(1.0f, 0.0f, 0.0f); } glBegin(GL_POLYGON); glVertex2i(25, 25); glVertex2i(75, 25); glVertex2i(75, 75); glVertex2i(25, 75); glEnd(); glFlush();
} int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(500, 500); glutCreateWindow("My App!"); glutDisplayFunc(display);
glutMouseFunc(mouse); gluOrtho2D(- 250.0, 250.0, -250.0, 250.0); glutMainLoop(); Trang 18
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh }
Lưu ý: Nếu không quan tâm trạng thái nhấn hay nhả nút, mà chỉ quan tâm
nút nào nhấn thì ta xét như sau if (button == GLUT_LEFT_BUTTON) { flag = 1; glutPostRedisplay();
cửa sổ vẽ sẽ có tọa ộ vẽ tương ứng là bao nhiêu. top left right bottom
glutInitWindowSize(winWidth, winHeight) gluOrtho2D(left, right, bottom, top) }
else if (button == GLUT_RIGHT_BUTTON) {
flag = 2; glutPostRedisplay(); }
5.2. Vị trí nhấp chuột
Trong các hàm xử lý sự kiện, x, y là vị trí hiện hành trong cửa sổ vẽ,
không phải là tọa ộ vẽ trên hệ tọa ộ vẽ. Ta có thể cũng muốn vẽ theo vị trí nhấp
chuột. Do các hàm vẽ sử dụng tọa ộ vẽ, nên ta cần biết vị trí nhấp chuột hiện hành trên
Công thức chuyển ổi từ vị trí (x,y) trên cửa sổ vẽ sang tọa ộ vẽ (x’, y’) là:
y' = ((bottom - top) / winHeight) * y + top;
x’ = ((right - left) / winWidth) * x + left;
Ví dụ: Vẽ các oạn thằng từ vị trí nhấp chuột thứ 0 ến thứ 1, thứ 1 ến thứ
2,…, thứ 18 ến thứ 19. Trang 19 Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com) lOMoAR cPSD| 48704538 ĐỒ HỌA MÁY TÍNH GV: Hồ Ngọc Thanh #include
//NUM là số lần tối a nhấp chuột #define NUM 20
//cấu trúc lưu mỗi iểm (vị trí) nhấp chuột. struct Point { int x, y; };
//Mảng lưu các iểm nhấp chuột Point points[NUM];
//biến lưu thứ tự cuối của iểm nhấp chuột, iểm ầu tiên có thứ tự 0 int
last = -1; //thứ tự -1 là chưa có iểm nhấp chuột
//GLfloat winWidth = glutGet(GLUT_SCREEN_WIDTH);
//GLfloat winHeight = glutGet(GLUT_SCREEN_HEIGHT); GLfloat winWidth = 500; GLfloat winHeight = 500;
GLfloat bottom = -winHeight/2, top = winHeight/2, left = -winWidth/2, right = winWidth/2;
//GLfloat bottom = 0, top = winHeight, left = 0, right = winWidth; void
mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && last < NUM - 1) {
++last; //thứ tự của iểm nhấp chuột points[last].y
= ((bottom - top) / winHeight) * y + top; points[last].x
= ((right - left) / winWidth) * x + left;
} else last = -1; //với giá trị này sẽ không
vẽ, tức là xóa glutPostRedisplay(); } void display() Trang 20
Downloaded by ANhh Trân (Anhhtrann14062003@gmail.com)