Qua ví dụ trên chúng ta thấy: hình vẽ thứ i của file Hinhve.mp được đặt trong dấu ngoặc của lệnh beginfigi, các lệnh vẽ hình được đưa vào sau đó và được phân cách bởi dấu ";".. Các nội d[r]
Trang 1VẼ HÌNH TRÊN LATEX VỚI METAPOST
ThS Trần Lê Nam - ThS Phan Thị Hiệp
1 Giới thiệu
Trong trình biên dịch LATEX, chúng ta có thể vẽ các hình từ các phần mềm và chèn chúng vào file TEX Tuy nhiên, các ảnh được chèn vào theo phương pháp này đều ở dạng bitmap Điều đó dẫn đến chất lượng bản in thấp, xuất ra file có dung lượng cao Hơn nữa, các phần mềm vẽ hình không cung cấp đủ các công cụ để vẽ các ảnh hình học Thêm vào đó, tính tương thích của mỗi loại ảnh với mỗi loại file xuất của LATEX
là khác nhau
Chính vì các lý do đó, cộng đồng người sử dụng TEX trên thế giới đã viết có gói lệnh, chương trình vẽ hình trực trên LATEX cho chất lượng ảnh cao như: gói pstricks, tikz, chương trình Metapost, Eukleides Trong số đó, chương trình biên dịch Metapost được đánh giá cao bởi những thông thạo về hình học
Metapost là một ngôn ngữ lập trình hình học được phát minh bởi John D Hobby, dựa trên hệ thống Metafont để tạo các fonts chữ đẹp được sáng tạo bởi Donald Knuth
Nó là một trình biên dịch xuất ra các file ảnh vector dưới dạng file *.mps Chúng có thể đưa trực tiếp vào file TEX để dịch ra ảnh *.dvi hay *.pdf
Trong bài báo, chúng tôi giới thiệu cách sử Metapost trên trình soạn thảo Winedt
để vẽ các hình và đồ thị trong chương trình toán học phổ thông Các chức năng mở rộng và nâng cao của Metapost sẽ được chúng tôi giới thiệu vào thời gian tới
2 Vẽ hình với Metapost
2.1 Ví dụ khởi đầu
− Trên Winedt, chúng ta tạo một file mới, đặt tên Hinhve.mp, nhập vào nội dung sau:
prologues:=3;
filenametemplate "%j_%c.mps";
beginfig(1);
pair A, B, C;
numeric u;
u:=1cm;
A:=(0,0);
B:=(3u,0);
C:=(u,2u);
draw A B C cycle;
label.lft(btex $A$ etex, A);
label.rt(btex $B$ etex, B);
label.top(btex $C$ etex, C);
endfig;
end;
Trang 2Sau đó, chúng ta nhấp tổ hợp phím Ctrl+Shift+M hay biểu tượng trên Winedt
để được file Hinhve_1.mps
− Tiếp theo, chúng ta tạo một file TEX cùng thư mục với file Hinhve.mp, để chèn hình vừa vẽ Đặt tên nó là Vehinh.tex và nhập vào nội dung sau:
\documentclass{minimal}
\usepackage{graphicx}
\begin{document}
\includegraphics{Hinhve_1.mps}
\end{document}
C
Hình 1: Tam giác ABC
Chạy file Vehinh.tex, chúng ta được hình một vẽ tam
giác ABC (Hình 1)
Phân tích cấu trúc file Hinhve.mp, chúng ta thấy nó
gồm 3 phần chính
+ Hai dòng đầu dùng để khai báo tạo ra kiểu file
*.mps
+ Các lệnh vẽ hình nằm giữa hai lệnh \beginfig(1);
và \endfig;
+ Lệnh end; kết thúc file
Qua ví dụ trên chúng ta thấy: hình vẽ thứ i của file Hinhve.mp được đặt trong dấu ngoặc của lệnh beginfig(i), các lệnh vẽ hình được đưa vào sau đó và được phân cách bởi dấu ";" Các nội dung tiếp theo của mục 2, chúng trình các kiểu dữ liệu, lệnh vẽ hình cơ bản và tùy chọn trong Metapost
2.2 Các kiểu dữ liệu trong Metapos
Metapost có 9 kiểu dữ liệu Trong số đó, chúng ta thường dùng các kiểu sau:
- numeric: dữ liệu về đại lượng như chiều dài, độ đo của góc
- pair: tọa độ của một điểm
- path: các đường thẳng hoặc đường cong
- transform: các phép biến hình
2.3 Khai báo một điểm trong Metapost
- Điểm A có tọa độ (x, y) trong mặt phẳng Euclid được khai báo bởi lệnh A=(x,y);
- Điểm A có tọa độ (r, θ) trong hệ tọa độ cực được khai báo bởi lệnh A=r*dir(θ);
top bot rt lft ulft urt
llft ulft
- Để đặt tên cho điểm A, chúng ta dùng lệnh: label.vt("A",A);
Ở đó vt là vị trí của nhãn A Nó nhận 1 trong tám vị trí như hình
bên Chúng ta dùng lệnh dotlabel thay cho lệnh label để thêm
một dấu chấm vào điểm cần đặt tên
Ví dụ: Khai báo điểm A(1, 2) trên mặt phẳng E2 và điểm B có mô-đun bằng 2√
2, góc bằng 450 trên mặt phẳng cực Đặt tên hai điêm đó là A, B
Trang 31
2
2
3
3
O
Hình 2: A(1, 2), B(2√
2, 450)
beginfig(3);
numeric u; u=1cm;
pair A,B;
A=(1,2)*u; B=2sqrt(2)*u*dir(45);
draw A withpen pencircle scaled 4bp;
draw B withpen pencircle scaled 4bp;
dotlabel.ulft("A",A);
dotlabel.urt("B",B);
endfig;
2.4 Vẽ đa giác
- Để vẽ đa giác qua các đỉnh A, B, , F ,
chúng ta dùng lệnh draw A B C F cycle
- Độ rộng của nét vẽ được xác đinh bởi lệnh withpen pencircle scaled ?bp;
- Để kẽ nét đức chúng ta dùng lệnh dashed evently
* Lưu ý: Để xác định độ rộng của toàn bộ đường trong hình vẽ, chúng ta dùng lệnh: pickup pencircle scaled ?bp;
Ví dụ: Vẽ hình chữ nhật và tứ diện
C D
Hình 3: Hình chữ nhật
beginfig(4);
pair A[];
numeric u; u=1cm;
pickup pencircle scaled 0.75bp;
A0=(0,0);A1=(4u,0);A2=(4u,3u);A3=(0,3u);
draw A0–A1–A2–A3–cycle;
dotlabel.lft("A",A0);
dotlabel.rt("B",A1);
dotlabel.rt("C",A2);
dotlabel.lft("D",A3);
endfig;
A
B
C D
Hình 4: Tứ diện
beginfig(5);
pair A[]; numeric u; u=1cm;
A0=(-2u,0);A1=(0,-2u);A2=(4u,0);A3=(u,4u);
pickup pencircle scaled 0.5bp;
draw A0–A1–A2–A3–A0;
draw A3–A1;
draw A0–A2 dashed evenly scaled 2;
label.ulft("A",A0);
label.lrt("B",A1);
label.urt("C",A2);
label.urt("D",A3);
endfig;
2.5 Tâm tỉ cự của 2 điểm
Cho trước hai điểm A, B, điểm C thỏa mãn
đẳng thức −→
AC = k−→
AB, k 6= 0, 1 được xác định bởi lệnh: C=k[A,B]
Trang 4Một điểm bất kì trên đường thẳng (AB) được xác định bởi lệnh whatever[A,B].
Từ đó, giao điểm C của hai đường thẳng (AB) và (EF ) được xác định bởi lệnh C=whatever[A,B]=whatever[E,F]
Ví dụ: Vẽ trọng tâm của một tam giác
A
M
N G
Hình 5: Trong tâm tam giác
beginfig(6);
pair a, b, c, m, n, g;
u:=1.2cm; a:=(u,2u); b:=(0,0); c:=(3u,0);
m:=1/2[b,c]; n:=1/2[a,c];
g:=whatever [a,m] = whatever [b,n];
draw a–b–c–cycle;
draw a–m;draw b–n;
label.top(btex A etex, a);
label.lft(btex B etex, b);
label.rt(btex C etex, c);
label.bot(btex M etex, m);
label.urt(btex N etex, n);
dotlabel.ulft(btex G etex, g);
endfig; 2.6 Vẽ đường tròn
Đường tròn tâm A đường kính 2r > 0 được
vẽ bằng lệnh: draw fullcircle scaled 2r shifted A
Ví dụ: vẽ đường tròn tâm A(1, 2) bán kính AB với B(3, 4)
A
B
-2
-2
-1 -1 1 1
2 2
3 3
4 4
5 5
0
beginfig(7);
pair A,B;
numeric u;
u=1cm;
A=(1cm,2cm); B=(3cm,4cm);
draw fullcircle scaled 2abs(A-B) shifted A;
dotlabel.top(btex A etex, A);
dotlabel.urt(btex B etex, B);
endfig;
2.7 Đường phân giác của một góc
Hàm angle(A-B) cho ra góc giữa trục Ox và véc-tơ −→
AB
A
M
Hình 6: Đường phân giác một góc
Giả sử AM là tia phân giác của góc [BAC
Chúng ta hãy tìm tọa độ của điểm M theo tọa độ
các điểm A, B, C
Theo Hình 6, chúng ta có góc tọa bởi véc-tơ
−−→
M A bằng 1/2 tổng của hai góc angle(B-A) và
angle(C-A) Do đó, tọa độ của điểm M có dạng
A + x.dir12(angle(B-A) + angle(C-A))
Do đó, trong metapost, chúng ta xác định một
điểm M nằm trên tia phân giác của góc [BAC
bởi lệnh:
M=A+whatever*dir(.5angle(B-A)+.5angle(C-A));
Trang 52.8 Phép biến hình trên mặt phẳng
Trong Metapost, chúng ta có các phép biến hình trên mặt phẳng sau:
(x; y) shifted (a; b) = (x + a; y + b);
(x; y) rotated (θ): phép quay quanh gốc tọa độ, góc quay θ
(x; y) rotatedaround ((a; b);θ) phép quay quanh điểm (a,b), góc quay θ
(x; y) slanted a = (x + ay; y);
(x; y) scaled a = (ax; ay): phép vị tự tâm O tỉ số a
(x; y) xscaled a = (ax; y);
(x; y) yscaled a = (x; ay);
(x; y) zscaled (a; b) = (ax -by; bx + ay):
Sử dụng các phép biến hình trên, chúng ta dựng được hầu hết các hình phẳng và hình trong không gian thường găp
Ví dụ: Vận dụng phép tịnh tiến và vị tự để dụng mặt cầu
O
beginfig(9);
numeric u; u=1.5cm; path d[];
pickup pencircle scaled 0.5bp;
d0=fullcircle scaled 3u;
d1=halfcircle scaled 0.85u;
d1:=d1 xscaled 3/0.85;
d2:=d1 yscaled -1;
draw d0; draw d2;
draw d1 dashed evenly;
dotlabel.top(btex O etex,(0,0));
endfig;
Ví dụ: Sử dụng phép quay, tịnh tiến để dựng đường
thẳng Euler
H I O C
A 1
C 1 C0
A0
beginfig(10);
numeric u;
pair A,B,C,H,O,I,Ap[],Bp[];
pickup pencircle scaled 0.5bp;
u=1.5cm;A=(-2,0)*u;B=(2,0)*u;C=(-0.5,3)*u;
Ap1=whatever[B,C]
= whatever[A,(B-C) rotated 90 shifted A];
Ap2=whatever[B,A]
=whatever[C,(B-A) rotated 90 shifted C];
H=whatever[A,Ap1]=whatever[C,Ap2];
Bp1=1/2[A,B];Bp2=1/2[B,C];
I=whatever[C,Bp1]=whatever[A,Bp2];
O=whatever[(A-B) rotated 90 +Bp1,Bp1]
=whatever[(B-C) rotated 90 +Bp2,Bp2];
draw fullcircle scaled 2abs(O-A) shifted O;
draw A–B–C–cycle;
draw A–Ap1; draw C–Ap2;
Trang 6draw C–Bp1;draw A–Bp2;
draw H–I–O–H;
draw O–Bp1; draw O–Bp2;
dotlabel.ulft(btex H etex,H); dotlabel.urt(btex I etex,I);
label.top(btex C etex,C); label.llft(btex A etex,A);
label.lrt(btex B etex,B); label.urt(btex A1 etex,Ap1);
label.bot(btex C1 etex,Ap2); label.bot(btex C0 etex,Bp1);
dotlabel.rt(btex O etex,O); label.urt(btex A0 etex,Bp2);
endfig;
Ví dụ: Vẽ đường tròn nội tiếp và bàn tiếp tam giác
I
O C
beginfig(11);
numeric u;
pair A,B,C,D,E,O,I,Ap[],Bp[];
u=1cm;
pickup pencircle scaled 0.5bp;
A=(-2,0)*u;B=(2.5,0)*u;C=(-0.5,3)*u;D=2.2[A,B];E=3[A,C];
Bp1=whatever[A,B]=whatever*dir(0.5angle(A-C)+0.5angle(B-C))+C; Bp2=whatever[A,C]=whatever*dir(0.5angle(A-B)+0.5angle(C-B))+B; O=whatever[C,Bp1]=whatever[B,Bp2];
I=whatever[(C-O) rotated 90 +C,C]=whatever[(B-O) rotated 90 +B,B]; Ap1=whatever[A,B]=whatever[(A-B) rotated 90+O,O];
Ap2=whatever[A,B]=whatever[(A-B) rotated 90+I,I];
draw A B C cycle;draw B D;draw C E;
draw C O;draw B O; draw C I; draw B I;
draw fullcircle scaled 2abs(O-Ap1) shifted O;
draw fullcircle scaled 2abs(I-Ap2) shifted I;
dotlabel.urt(btex $I$ etex,I); dotlabel.ulft(btex $O$ etex,O); label.ulft(btex $C$ etex,C); label.llft(btex $A$ etex,A);
label.lrt(btex $B$ etex,B);
endfig;
2.9 Vòng lập xác định
Vòng lập xác định for có cấu trúc:
Trang 7for i=gt_ban_dau step gt_tang until gt_cuoi:
Hệ lệnh;
endfor;
Thay vì dùng step 1 until, chúng ta có thể dùng upto Tương tự, downto thay cho step -1 until
Ví dụ: Vẽ đồ thị hàm số y = x2 với x ∈ (−2, 2)
1 2 3
4
y= x 2
beginfig(12);
numeric u,i; path p; u=1cm;
p=(-2,(-2)*(-2))*u
for i=-2+0.1 step 0.1 until 2.1:
(i,i*i)*u
endfor;
for i=-3 upto 3:
label.bot(decimal(i), (i,0)*u);
draw (i,-0.05)*u–(i,0.05)*u;
endfor;
for i=1 upto 4:
label.rt(decimal(i), (0,i)*u);
draw (-0.05,i)*u–(0.05,i)*u;
endfor;
drawarrow (-3.5u,0)–(3.5u,0);drawarrow(0,-u)–(0,4.5u);
draw p withpen pencircle scaled 1bp;
endfig;
2.10 Xây dựng một đường cong đóng
Lệnh buildcycle(p1, p2, , pm) tạo ra một đường cong đóng từ các đường pi Sau khi tạo ra được một đường cong đóng, chúng ta dùng lệnh
fill duong_cong withcolor mau;
để tô màu miền trong của nó
Ví dụ: Minh họa diện tích hình phẳng
x
y
f (x)
beginfig(13);
numeric xmin, xmax, ymin, ymax; xmin := 1/2;
xmax := 6; ymax := 2/xmin;
u := 1cm; xinc := 0.1;
path pts_f;
pts_f := (xmin,2/xmin)*u
for x=xmin+xinc step xinc until xmax:
(x,2/x)*u
endfor;
path hline[], vline[];
hline0 = (-0.5,0)*u – (xmax+0.5,0)*u;
vline0 = (0,-0.5)*u – (0,ymax+0.5)*u;
vline0.5 = (0.75,0)*u – (0.75,ymax)*u;
vline4 = (4,0)*u – (4,ymax)*u;
Trang 8fill buildcycle(hline0, vline0.5, pts_f, vline4) withcolor blue;
drawarrow hline0;
drawarrow vline0;
draw (0.75,0)*u – vline0.5 intersectionpoint pts_f
draw (4,0)*u – vline4 intersectionpoint pts_f
draw pts_f withpen pencircle scaled 1bp;
label.bot(btex x etex, (xmax,0)*u);
label.lft(btex y etex, (0,ymax)*u);
label.urt(btex f (x) etex, (2,1)*u);
endfig;
Trong ví dụ trên, lệnh intersectionpoint dùng để xác định giao điểm của hai đường cong
2.11 Xén một hình
Lệnh clip p to q; dùng để cắta hình p theo một đường cong q và giữ lại phần ở miền trong của q
Ví dụ: Vẽ thiết diện của một tứ diện
A
B
C
D
P
Q
R
beginfig(14);
pair A[],B[]; numeric u,i; path p,c;u=1cm;
A0=(-2u,0);A1=(0,-2u);A2=(4u,0);A3=(u,4u);
B0=1/2[A0,A2];B1=1/2[A2,A1];B2=1/2[A2,A3];
p=B0–B1–B2–cycle;
c:=-500*dir(15)–500*dir(15);
for i=0 upto 25:
draw c shifted (0,5*i);
draw c shifted (0,-5*i);
endfor;
clip currentpicture to p;
pickup pencircle scaled 0.75bp;
draw A0–A1–A2–A3–A0; draw A3–A1;
draw A0–A2 dashed evenly scaled 2 shifted (10,0);
draw B2–B0–B1 dashed evenly scaled 1;
draw B1–B2;
dotlabel.ulft("A",A0); dotlabel.lrt("B",A1); dotlabel.urt("C",A2);
dotlabel.urt("D",A3); dotlabel.ulft("P",B0); dotlabel.lrt("Q",B1); dotlabel.urt("R",B2); endfig;
Ví dụ: Vẽ hình cánh quạt
beginfig(2);
path p[],a,q; numeric u; u=1cm;
pickup pencircle scaled 0.5;
p0=halfcircle scaled 6u;
p1=halfcircle scaled 1u shifted (-2.5u,0);
p2=halfcircle scaled 1u shifted (2.5u,0);
p3=halfcircle scaled 4u yscaled -1;
q=buildcycle(reverse(p1),reverse(p3),reverse(p2),p0);
a=-6u*dir(30)–6u*dir(30);
for i=-30 upto 22:
Trang 9draw a shifted (i*u/5,0);
endfor;
clip currentpicture to q;
draw q withpen pencircle scaled 1bp;
endfig;
3 Kết luận
TÀI LIỆU THAM KHẢO
1 John D Hobby, A user’s manual for MetaPost, AT&T Bell Laboratories Com-puting Science Technical Report 162, 1992
2 André Heck, Learning MetaPost by doing, AMSTEL Institute, Universiteit van Amsterdam, 2005