Idle Works, Idle Thoughts

MetaPost学习笔记

MetaPost是一种绘图语言,可以用它精确控制图像。以下是MetaPost的基础语法,你也可以通过我的MetaPost实例代码快速入门。

MetaPost基础知识

注意到赋值符号是:=而非=。=用在求解线性方程(Linear Equations)的场合,例如:

a+b=3; 2a=b+3;

MetaPost可以推算出a=2、b=3。因为=不是赋值符,因此a=a+1必然会导致错误(输出inconsistent equation),正确的自增1的方式:

a := a+1;

MetaPost数据类型

MetaPost提供10种数据类型,分别是:

boolean, string, color, numeric, pair, path, pen, picture, transform, path

默认数据类型是 numeric,因此如果变量不作声明的话,就被视作 numeric 。

例如,你可以直接写:

n = 10;

相当于:

numeric n;
n = 10;

对其他类型的变量,必须先声明,再赋值,如:

pair p;
p = (0,0);

boolean

boolean的取值是true或false。

这些操作符会返回boolean值:

=, <>, <, <=, >, =>
not
and, or

注意不等于写作<>,大于等于写作=>,逻辑取反是not

有2种谓词(predicates)。

数据类型的名字可作为谓词,如:

color c
path p

其他谓词:

odd n (n is odd)
cycle p (path p is a cycle)
known x (x has a value)
unkown x (x doesn't have a value)

判断n是奇数,用odd n; 判断n是偶数,用not odd n

numeric

numeric的取值范围是:[ 2-16 = 1/65536, 4096 ]。

输出numeric的值:

i := 0;
label.top(decimal(i), (0,0))

Box

画一个盒子:

boxit.a(btex $box$ etex);
drawboxed(a);

画两个盒子并排着:

boxjoin(a.e=b.w)
boxit.a(btex $A$ etex);
boxit.b(btex $B$ etex);
drawboxed(a,b);

画两个盒子,中间间隔 1cm:

boxit.a(btex $A$ etex);
boxit.b(btex $B$ etex);
b.w = a.e + (1cm,0); 
drawboxed(a,b);

从盒子 A 画个箭头指向盒子 B:

boxit.a(btex $A$ etex);
boxit.b(btex $B$ etex);
b.w = a.e + (1cm,0); 
drawboxed(a,b);
drawarrow a.e -- b.w;

两个盒子相互指向:

boxit.a(btex $A$ etex);
boxit.b(btex $B$ etex);
b.w = a.e + (1cm,0); 
drawboxed(a,b);
drawarrow a.n {dir 90} .. {dir -90} b.n;
drawarrow b.s {dir -90} .. {dir 90} a.s;

盒子模型:

u := 1cm;

% outside box

pair a,b,c,d;
a = (0,0); b = (0,4u);
c = (4u,4u); d = (4u,0);
draw a--b--c--d--cycle;

% inside box

pair e,f,g,h;
e = (1u,1u); f = (1u,3u);
g = (3u,3u); h = (3u,1u);
fill e--f--g--h--cycle withcolor .8white;

% draw arrows

drawdblarrow 1/2[a,b] -- 1/2[e,f];
drawdblarrow 1/2[b,c] -- 1/2[f,g];
drawdblarrow 1/2[c,d] -- 1/2[g,h];
drawdblarrow 1/2[a,d] -- 1/2[e,h];

label.top(btex $dx$ etex, 1/2[1/2[a,b], 1/2[e,f]]);
label.top(btex $dx$ etex, 1/2[1/2[c,d], 1/2[g,h]]);
label.rt(btex $dy$ etex, 1/2[1/2[b,c], 1/2[f,g]]);
label.rt(btex $dy$ etex, 1/2[1/2[a,d], 1/2[e,h]]);

% draw dots

pickup pencircle scaled 4pt;
dotlabel.urt(btex $c$ etex, 1/2[a,c]);
dotlabel.top(btex $n$ etex, 1/2[b,c]);
dotlabel.bot(btex $s$ etex, 1/2[a,d]);
dotlabel.lft(btex $w$ etex, 1/2[a,b]);
dotlabel.rt(btex $e$ etex, 1/2[c,d]);

dotlabel.lft(btex $sw$ etex, a);
dotlabel.lft(btex $nw$ etex, b);
dotlabel.rt(btex $ne$ etex, c);
dotlabel.rt(btex $se$ etex, d);

杂项

坐标系(Coordinates)

MetaPost的坐标系和我们直观理解的一样。X轴从原点向右延伸,Y轴从原点向上延伸。

Default Coordinates

drawarrow (0,0) -- (0,50);
drawarrow (0,0) -- (50,0);
dotlabel.llft(btex (0,0) etex, (0,0));
label.rt(btex X etex, (50,0));
label.top(btex Y etex, (0,50));