跳转至

MetaPost、MetaFun学习笔记

主要是学习官方文档METAPOST manual、metafun(metafun-p.pdf)和metafun xl(luametafun.pdf),以及官网。

惯例#

在ConTeXt中使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
\starttext

% 就地插入图片
\startMPcode
fill unitsquare scaled 5cm withcolor red ;
\stopMPcode

% 插入mp页
\startMPpage
fill fullcircle scaled 5cm withcolor red ;
\stopMPpage

% 生成指定名字的图片,再使用
\startuseMPgraphic{name}
fill unitsquare scaled 5cm withcolor red ;
\stopuseMPgraphic
\useMPgraphic{name}

\stoptext

欢迎来到MetaPost#

坐标点,数值对(pair),矢量,路径,控制点。

1
2
pair somepoint;
somepoint := (1cm,1.5cm) ;

路径#

1
2
3
4
5
(1cm,1cm)..(1.5cm,1.5cm)..(2cm,0cm) % 开放路径,平滑曲线
(1cm,1cm)--(1.5cm,1.5cm)--(2cm,0cm) % 开放路径,直线
(1cm,1cm)..(1.5cm,1.5cm)..(2cm,0cm)..cycle % 闭合路径
(1cm,1cm)..(1.5cm,1.5cm)..controls (3cm,2cm)..(2cm,0cm) % 控制点,左右两个点共用
(1cm,1cm)..controls (.5cm,2cm) and (2.5cm,2cm)..(2cm,.5cm) % 控制点,左右分别定义

变形#

变量和赋值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
path p ; % 定义路径变量
p := (1cm,1cm)..(1.5cm,2cm)..(2cm,0cm) ; % 赋值
p shifted (4cm,2cm) % 位移
p rotated 15 % 旋转,等于:
p rotatedaround (origin, 15) 
p rotatedaround(center p, 15) shifted (4cm,0cm) % 联合操作
p slanted 1.5 shifted (4cm,0cm) % 倾斜
p reflectedabout((2.4cm,-.5),(2.4cm,3cm)) % 镜像反射

transform t ; % 变形变量
t := identity scaled 2cm shifted (4cm,1cm) ; % 变形矩阵
p transformed t
METAPOST code mathematical equivalent
(x,y) shifted (a,b) (𝑥 + 𝑎, 𝑦 + 𝑏)
(x,y) scaled s (𝑠𝑥, 𝑠𝑦)
(x,y) xscaled s (𝑠𝑥, 𝑦)
(x,y) yscaled s (𝑥, 𝑠𝑦)
(x,y) zscaled (u,v) (𝑥𝑢 − 𝑦𝑣, 𝑥𝑣 + 𝑦𝑢)
(x,y) slanted s (𝑥 + 𝑠𝑦, 𝑦)
(x,y) rotated r (𝑥 cos(𝑟) − 𝑦 sin(𝑟), 𝑥 sin(𝑟) + 𝑦 cos(𝑟))

构造路径#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
z0 = (0.5cm,1.5cm) ;
z1 = (2.5cm,2.5cm) ;
z2 = (6.5cm,0.5cm) ;
z3 = (3.0cm,1.5cm) ;

z0--z1--z2--z3--cycle
z0..z1..z2..z3..cycle
z0...z1...z2...z3...cycle % 紧闭合
z0---z1---z2---z3---cycle % 紧闭合,看不见控制点
z0..z1..z2--z3..cycle % 折线过度
z0..z1..z2---z3..cycle % 曲线过度
z0..z1..z2 & z2..z3..z0 & cycle % 连接子路径
z0..z1..z2..z3..z0 % 看似闭合的开放路径
z0..z1..z2..z3..z0..cycle % 如此闭合
buildcycle(z0..z1..z2 , z0..z3..z1..cycle) % 用点和多个路径构造闭合路径
z0--z1 softjoin z2--z3 % 松开一个结点
subpath(2,4) of (z0..z1..z2..z3..cycle) % 提取子路径,可以是小数
(z0..z1..z2..z3) cutafter z2 % 剪除路径
(z0..z1..z2..z3) cutbefore z1
(z0..z1..z2..z3) cutbefore point 2 of (z0..z1..z2..z3) % 剪除路径,可以是小数

预定义的directionpoint

  • right ( 1, 0)
  • up ( 0, 1)
  • left (-1, 0)
  • down ( 0,-1)
1
2
(z0..z1..cycle) cutafter directionpoint up of (z0..z1..cycle)
(z0..z1..cycle) cutafter directionpoint (1,1) of (z0..z1..cycle)

角度#

方向函数dir

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
pickup pencircle scaled 2mm ;

draw (origin -- dir(45) -- dir(0) -- cycle)
scaled 3cm
withcolor .625red ;

draw (origin -- dir(angle(1,1)) -- dir(angle(1,0)) -- cycle)
scaled 3cm shifted (3.5cm,0) withcolor .625yellow ;

draw (origin -- (1,1) -- (1,0) -- cycle)
scaled 3cm shifted (7cm,0)
withcolor .625white ;

画图#

根据路径画线和填充

1
2
3
draw (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..cycle ;

fill (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..cycle ;

颜色,笔型,线型

1
2
3
4
path p ; 
p := (0cm,1cm)..(2cm,2cm)..(4cm,0cm)..(2.5cm,1cm)..cycle ;
drawarrow p withcolor .625red ;
draw p shifted (7cm,0) dashed withdots withcolor .625yellow ;

图形变量,赋值,清空,操纵

1
2
3
4
picture pic ;
pic := currentpicture ;
currentpicture := nullpicture ;
draw pic rotated 45 withcolor red ;

unfill其实是使用背景色填充

添加

1
2
3
addto currentpicture doublepath pat
addto currentpicture contour pat
addto currentpicture also pic

变量#

METAPOST是一种简单的宏语言,用PASCAL编写而成。

数据类型:

numeric real number in the range −4096… + 4096
boolean a variable that takes one of two states: true or false
string sequence of characters, like "metapost"
pair point or vector in 2--dimensional space
path a piecewise collection of curves and line segments
picture collection of stroked or filled paths
color vector of three (rgb) or four (cmyk) numbers
pen pen specification
transform transformation vector with six elements

十种基础数据类型:

  • numeric, 1/65536(epsilon)的整数倍
  • pair, 数对,可进行四则运算,可用于区间定位表达式(mediation expressions)
  • path,路径
  • transform,变换组合,包括旋转、缩放、倾斜、位移的组合,可用于数对、路径、图像、笔和变换自身。
  • color/rgbcolor,三元数组,运算同数对(结果会修剪到0与1之间)。也指预定义的常量:
    • black,(0,0,0)
    • white,(1,1,1)
    • red
    • green
    • blue
  • cmykcolor,四元数组,运算同color,小心纯黑色(0,0,0,1)与混色黑(1,1,1,𝑘)(𝑐,𝑚,𝑦,1)的在印刷实际中的区别
  • string,"...",不能包括双引号和换行,但可以通过n := scantokens(str);输入
  • boolean
    • true, false
    • and, or, not
    • =, <>, <, >, <=, >=
  • picture, 任何可绘制对象,draw把绘制结果存在currentpicture,图像可叠加和变换
  • pen, 主要确定笔画粗细,表达式如pencircle scaled ⟨numeric primary⟩,非圆形笔可以取得书法效果,pickup ⟨pen expression⟩ 影响会面的draw和drawdot

未定义的变量默认为数字。以下行相同:

1
2
n := 10 ;
numeric n ; n := 10 ;

在宏集中最好先定义,以免冲突。

数组是同类变量的集合:

1
numeric n[][] ; n[2][3] := 10 ;

超界索引不会出错,而返回unknown

实际上并没有数组,而是生成了一些哈希条目。以下是定价的:

1
2
3
i_111_222 := 1cm ;
i_[111]_[222] := 1cm ;
i_[111][222] := 1cm ;

变量后缀#

如lable后缀:<空> | lft | rt | top | bot | ulft | urt | llft | lrt

z后缀,如:

dotlabels.rt(0, 1, a); % 等价于dotlabel.rt("0",z0); dotlabel.rt("1",z1); dotlabel.rt("a",z.a);

token#

运算符#

条件表达式#

1
2
3
if n=10 : draw p ;
else : draw q ;
fi ;

一行式:

1
2
draw if n=10 : p else : q fi withcolor red ;
draw p withcolor if n<10 : red elseif n=10 : green else : blue fi ;

变量的布尔检测:

1
2
3
4
if picture p :
if known   n :
if odd     i :
if cycle   q :

支持用and, or, not, 和 ( )构造表达式。

循环#

1
2
3
4
5
for i=0 step 2 until 20 :
    draw (0,i) ;
endfor ;

draw for i=0 upto n-1 : p[i] .. endfor p[n] ;

迭代一列对象:

1
2
3
4
for i=p,q,r :
    fill i withcolor .8white ;
    draw i withcolor red ;
endfor ;

改变循环变量自身:

1
2
3
forsuffixes i = p, q, r :
i := i shifted (3cm,2cm) ;
endfor ;

查找特定值后跳出/终止循环:

1
2
3
4
5
6
7
8
numeric done[][], i, j, n ; n := 0 ;
forever :
    i := round(uniformdeviate(10)) ; j := round(uniformdeviate(2)) ;
    if unknown done[i][j] :
        drawdot (i*cm,j*cm) ; n := n + 1 ; done[i][j] := n ;
    fi ;
    exitif n = 10 ;
endfor ;

#

定义宏:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def upto = step 1 until enddef ;

primarydef p doublescaled s =
    p xscaled (s/2) yscaled (s*2)
enddef ;
draw somepath doublescaled 2cm withcolor red ;
% 实际展开为:
% draw somepath xscaled 1cm yscaled 4cm withcolor red ;

def drawrandomscaledpath (expr p, s) =
    draw p xscaled (s/2) yscaled (s*2) ;
enddef ;

% 返回变量的定义,返回最后一句的结果,而不是展开(因此不要使用分号结尾)
vardef randomscaledpath(expr p, s) =
    numeric r ; r := round(1 + uniformdeviate(4)) ;
    p xscaled (s/r) yscaled (s*r)
enddef ;

可接受的参数:

  • expr: something that can be assigned to a variable
  • text: arbitrary METAPOST code ending with a ;
  • suffix: a variable bound to another variable
  • primary

expr是传值的,suffix则是传引用。

默认所有变量都是全局的,局部变量需要通过分组来管理。

1
2
3
4
5
6
7
% 实际上,vardef会自动分组
vardef randomscaledpath(expr p, s) =
    begingroup ; save r ; numeric r ; % save r 定义局部变量
        r := round(1 + uniformdeviate(4)) ;
        p xscaled (s/r) yscaled (s*r)
    endgroup
enddef ;

其他定义:

  • primarydef x mod y = ... enddef ;
  • secondarydef p intersectionpoint q = ... enddef ;
  • tertiarydef p softjoin q = ... enddef ;

参数#

馈送参数相当灵活:

1
2
3
4
5
6
7
8
def test expr a = enddef ; test (a) ; test a ;
def test (expr a) = enddef ; test (a) ; test a ;

def test (expr a,b) (expr c,d) = enddef ;
test (a) (b) (c) (d) ;
test (a,b) (c,d) ;
test (a,b,c) (d) ;
test (a,b,c,d) ;

text参数,如果没有括号限制,会一直匹配到分号。

限定参数,用于定义z1或z234:

vardef z@# = (x@#,y@#) enddef ;

笔型#

绘图时可以使用三种属性:a dashpattern, a pen and/or a color

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
withpen pencircle

% 改变当前笔型
pickup pencircle xscaled 2mm yscaled 4mm rotated 30 ;

% 自定笔型,使用makepen和makepath转换路径和笔型
path p ; p := fullcircle xscaled 2cm yscaled 3cm ;
pen doublepen ; doublepen := makepen ((0,0)--(.3cm,.3cm)) ;
pickup doublepen ; draw p ;
% 就地使用
draw p withpen makepen ((0,0)--(.3cm,.3cm)) ;

% 显示笔型框架
path p ; p := (-1,0) {down} .. {up} (1,0) ;
draw pensilled(p, pensquare scaled (1/3) rotated 30)
    scaled 2cm ;
draw boundingbox image(draw p)
    scaled 2cm ;

连接线段#

1
2
3
4
5
6
interim linejoin := mitered ;
for i :=1 step 1 until 5 :
    interim miterlimit := i*pt ;
    draw ((0,0)--(.5,1)--(1,0)) shifted (1.5i,0) scaled 50pt
    withpen pencircle scaled 10pt withcolor .625red ;
endfor ;

参见:Figure 1.3 The nine ways to end and join lines.

颜色#

1
2
3
4
5
6
7
8
withcolor (.4,.5.,6)

color darkred ; darkred := (.625,0.0) ;
withcolor darkred

withcolor .625red

withcolor .5[red,green]

虚线#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
picture p ; p := nullpicture ;
addto p doublepath ((0,0)--(3mm,3mm)) shifted (6mm,6mm) ;
draw (0,0)--(10cm,0) dashed p withpen pencircle scaled 1mm ;

% 更方便
picture p ; p := dashpattern(on 3mm off 3mm) ;
draw (0,0)--(10cm,0) dashed p withpen pencircle scaled 1mm ;

% 直接使用开关式图像evenly
draw (0,0)--(10cm,0) dashed (evenly scaled 1mm)
withpen pencircle scaled 1mm ;

% 设置默认值
drawoptions(dashed evenly withcolor red) ;

文本#

  • label⟨标签后缀⟩(⟨字符串或图片表达式⟩, ⟨数对表达式⟩);
    • thelabel⟨标签后缀⟩(⟨字符串或图片表达式⟩, ⟨数对表达式⟩); % 返回图像原语
  • dotlabel⟨标签后缀⟩(⟨字符串或图片表达式⟩, ⟨数对表达式⟩);
    • dotlabels.rt(0, 1, a); % z后缀,等价于dotlabel.rt("0",z0); dotlabel.rt("1",z1); dotlabel.rt("a",z.a);
  • ⟨标签后缀⟩ -> <空> | lft | rt | top | bot | ulft | urt | llft | lrt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
pair a ; a := (3cm,3cm) ;
label.top("top",a) ; label.bot("bot",a) ;
label.lft("lft",a) ; label.rt ("rt" ,a) ;

pair a ; a := (3cm,3cm) ;
dotlabel.top("top",a) ; dotlabel.bot("bot",a) ;
dotlabel.lft("lft",a) ; dotlabel.rt ("rt" ,a) ;

pair a ; a := (3cm,3cm) ; pickup pencircle scaled 1mm ;
drawdot a withcolor .625yellow ;
draw thelabel.rt("the right way",a) withcolor .625red ;

% 标签排版btex..etex和textext()会生成图像原语
% 使用字体(infont不支持居中、字间等,但是在ConTeXt中与btex无异,因为infont已经重载为,二者都是用textext,即重定向到tex)
draw "this string will become a sequence of glyphs (MP)" infont defaultfont scaled defaultscale ;
draw btex this string will become a sequence of glyphs (\TeX) etex ;

改变默认字体、字号:

  • defaultfont:="ptmr8r";
  • defaultscale:= 1.2; % 1是默认值
  • defaultscale:= 12pt/fontsize defaultfont;

绑定盒bbox与文本测量

线性方程#

解析线性方程(符号计算)

1
2
3
4
a + b = 3;
2a = b +3;
c = 1/2[a,b]; % 两点之间的比例位置
show a, b, c; % 跟踪变量

剪裁#

取得外框数据:

  • llcorner p: lower left corner
  • lrcorner p: lower right corner
  • urcorner p: upper right corner
  • ulcorner p: upper left corner
  • center p: the center point
1
2
3
4
5
6
fill fullcircle scaled 2cm withcolor .625yellow ;
setbounds currentpicture to unitsquare scaled 1cm ; % 重置外框
draw unitsquare scaled 1cm withcolor .625red ;

fill fullcircle scaled 2cm withcolor .625yellow ;
clip currentpicture to unitsquare scaled 1cm ; % 剪裁

METAFUN扩展#

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
% 缩放:enlarged,bottomenlarged, rightenlarged, topenlarged and leftenlarged
path p ; p := fullsquare scaled 2cm ;
drawpath p ; drawpoints p ;
p := (p shifted (3cm,0)) enlarged (.5cm,.25cm) ;
drawpath p ; drawpoints p ;

% 圆角
path p ; p := ((1,0)--(2,0)--(2,2)--(1,2)--(0,1)--cycle)
xysized (4cm,2cm) ;
drawpath p ; drawpoints p ;
p := (p shifted (5cm,0)) cornered .5cm ;
drawpath p ; drawpoints p ;

% 平滑,会改变大形状
path p ; p := ((1,0)--(2,0)--(2,2)--cycle) xysized (4cm,2cm) ;
drawpath p ; drawpoints p ;
p := (p shifted (5cm,0)) smoothed .5cm ;
drawpath p ; drawpoints p ;

% 简化路径(重复的点)
path p ; p := ((0,0)--(1,0)--(2,0)--(2,1)--(2,2)--(1,2)--(0,2)--(0,1)--cycle) xysized (4cm,2cm) ;
drawpath p ; drawpoints p ;
p := simplified (p shifted (5cm,0)) ;
drawpath p ; drawpoints p ;

% 去除路径毛刺(重叠路径)
path p ; p := ((0,0)--(2,0)--(3,1)--(2,0)--(2,2)--(1,2)--(1,3)--(1,2)--(0,1)--cycle) xysized (4cm,2cm) ;
drawpath p ; drawpoints p ;
p := unspiked (p shifted (5cm,0)) ;
drawpath p ; drawpoints p ;

% 随机扭曲
path p ; p := fullsquare scaled 2cm ;
drawpath p ; drawpoints p ;
p := (p shifted (5cm,0)) randomized .5cm ;
drawpath p ; drawpoints p ;

% 挤压
path p ; p := fullsquare scaled 2cm randomized .5cm ;
drawpath p ; drawpoints p ;
p := (p shifted (5cm,0)) squeezed .5cm ;
drawpath p ; drawpoints p ;

% 朋克(减少平滑,缩小)
path p ; p := fullcircle scaled 2cm randomized .5cm ;
drawpath p ; drawpoints p ;
p := punked (p shifted (5cm,0)) ;
drawpath p ; drawpoints p ;

% 平滑(变大)
path p ; p := fullsquare scaled 2cm randomized .5cm ;
drawpath p ; drawpoints p ;
p := curved (p shifted (5cm,0)) ;
drawpath p ; drawpoints p ;

% 阶梯化
path p ; p := fullcircle scaled 3cm ;
drawpath p ; drawpoints p ;
p := laddered (p shifted (5cm,0)) ;
drawpath p ; drawpoints p ;

% 并列,比如画化学分子式
path p ; p := fullcircle scaled 3cm ;
drawpath p ; drawpoints p ;
p := p paralleled 1cm ;
drawpath p ; drawpoints p ;

% 膨胀
path p ; p := fullsquare xyscaled (4cm,1cm) randomized .5cm ;
drawpath p ; drawpoints p ;
p := p blownup .5cm ;
drawpath p ; drawpoints p ;

% 伸缩,仅应用与直线路径
path p ; p := (0,0) -- (2cm,3cm) ;
drawpath p ; drawpoints p ;
p := p shortened 1cm ;
drawpath p ; drawpoints p ;
p := p shortened -1cm ;
drawpath p ; drawpoints p ;

% 圆角矩形
path p ; p := roundedsquare(2cm,4cm,.25cm) ;
drawpath p ; drawpoints p ;

% 圆方/方圆,张力圆
path p ; p := tensecircle(2cm,4cm,.25cm) ;
drawpath p ; drawpoints p ;

% 取得路径上的某个位置的点
path p, q, r ;
p := fullsquare xyscaled (2cm,2cm) randomized .5cm ;
q := p shifted (3cm,0) ; r := q shifted (3cm,0) ;
drawpath p ; drawpoints p ; drawpointlabels p ;
drawpath q ; drawpoints q ; drawpointlabels q ;
drawpath r ; drawpoints r ; drawpointlabels r ;
pickup pencircle scaled 5mm ;
draw point 2.25 of p withcolor .625red ;
draw point 2.50cm on q withcolor .625yellow ;
draw point .45 along r withcolor .625white ;

% 剪切路径
path p ; p := (0cm,0cm)
-- (4cm,1cm) ;
path q ; q := (5cm,0cm){right} .. (9cm,1cm) ;
drawpath p ; drawpoints p ; drawpath q ; drawpoints q ;
p := p cutends .5cm ; q := q cutends .5cm ;
drawpathoptions (withpen pencircle scaled 5pt withcolor .625yellow) ;
drawpointoptions(withpen pencircle scaled 4pt withcolor .625red) ;
drawpath p ; drawpoints p ; drawpath q ; drawpoints q ;
resetdrawoptions ;

path p ; p := (0cm,0) .. (4cm,0) .. (8cm,0) .. (4cm,0) .. cycle ;
drawpath p ; drawpoints p ; p := p cutends (2cm,1cm) ;
drawpathoptions (withpen pencircle scaled 5pt withcolor .625yellow) ;
drawpointoptions(withpen pencircle scaled 4pt withcolor .625red) ;
drawpath p ; drawpoints p ;
resetdrawoptions ;

% 拉伸路径,零点不变
path p ; p := (0cm,0) .. (3cm,1cm) .. (4cm,0) .. (5cm,1cm) ;
drawpath p ; drawpoints p ; p := p stretched 1.1 ;
drawpathoptions (withpen pencircle scaled 2.5pt withcolor .625yellow) ;
drawpointoptions(withpen pencircle scaled 4.0pt withcolor .625red) ;
drawpath p ; drawpoints p ; resetdrawoptions ;

% 指定零点后拉伸
path p ; p := (0cm,0) .. (3cm,1cm) .. (4cm,0) .. (5cm,1cm) ;
drawpath p ; drawpoints p ; p := p stretched (.75,1.25) ;
drawpathoptions (withpen pencircle scaled 2.5pt withcolor .625yellow) ;
drawpointoptions(withpen pencircle scaled 4.0pt withcolor .625red) ;
drawpath p ; drawpoints p ; p := p stretched (0,1.5) ;
drawpathoptions (withpen pencircle scaled 4.0pt withcolor .625red) ;
drawpointoptions(withpen pencircle scaled 2.5pt withcolor .625yellow) ;
drawpath p ; drawpoints p ; resetdrawoptions ;

% randomized随机化可以应用于numeric, pair, path and color
draw fullsquare xyscaled (4cm,2cm)
randomized .25cm
shifted origin randomized (1cm, 2cm)
withcolor red randomized (.625, .850)
withpen pencircle scaled (5pt randomized 1pt) ;

% xy缩放, METAPOST本身只有scaled, xscaled and yscaled
picture p ; p := image
( draw fullsquare
xyscaled (300,800)
withpen pencircle scaled 50
withcolor .625 yellow ; ) ;
draw p xysized (3cm,2cm) shifted (bbwidth(currentpicture)+.5cm,0) ;
draw p xysized 2cm shifted (bbwidth(currentpicture)+.5cm,0) ;
draw p xsized 1cm shifted (bbwidth(currentpicture)+.5cm,0) ;
draw p ysized 2cm shifted (bbwidth(currentpicture)+.5cm,0) ;

% 画出外框
draw fullcircle scaled 1cm
withcolor .625red
withpen pencircle scaled 1mm ;
draw currentpicture
withcolor .625yellow withpen pencircle scaled 3mm ;
draw boundingbox currentpicture
withpen pencircle scaled .5mm ;

% 画出背景
fill fullcircle scaled 1cm withcolor .625red ;
addbackground withcolor .625 yellow ;

剪切和粘贴#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
vardef somearrow (expr pat, loc, len) =
    save p ; path p ; p := pat cutbefore loc ; % 剪掉指定位置前
    (p cutafter point (arctime len of p) of p) % 剪掉指定点(弧长)后
enddef ;

path p ; p := fullcircle scaled 3cm ;
pair q ; q := point .4 along p ;
pickup pencircle scaled 2mm ;
draw p withcolor .625white ;
drawarrow somearrow(p,q,2cm) withcolor .625red ;
draw q withcolor .625yellow ;

当前图像(currentpicture)#

我们绘画时是在当前图像上操作。还可以把当前图像当做一个整体来处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ;
currentpicture := currentpicture slanted .5 ;

draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ;
currentpicture := currentpicture slanted .5 ;
pushcurrentpicture ; % 压栈暂存
draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625yellow ;
currentpicture := currentpicture slanted -.5 ;
popcurrentpicture ; % 弹出

% 或使用METAFUN的变体image
draw fullcircle scaled 1cm withpen pencircle scaled 1mm withcolor .625red ;
currentpicture := currentpicture slanted .5 ;
draw image (
    draw fullcircle scaled 1cm
    withpen pencircle scaled 1mm withcolor .625yellow ;
    currentpicture := currentpicture slanted -.5 ;
) ;

更多细节#

生成图形(graphic)#

独立文件,比如yourfile.mp:

1
2
3
4
5
6
7
8
9
% Let's draw a circle.
% input mp-tool ;
% or input metafun ;
beginfig (7) ;
    % 生成svg格式,否则是POSTSCRIPT格式
    % outputformat := "svg" ;
    draw fullcircle scaled 3cm withpen pencircle scaled 1cm ;
endfig ;
end .

在CONTEXT文档中不需要beginfig (7) ; endfig ;和end .

生成图像文件:

1
mpost yourfile.mp

使用图像:

\externalfigure[yourfile.7]

单位:

  • cm
  • pt, point
  • bp, big point, METAPOST的缺省单位,对应pt的POSTSCRIPT的近似值

围盒#

bbox宏生成的围盒是有偏置量的。偏置量控制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
% 绘制(在路径上/两侧)
pickup pencircle scaled .5cm ;
draw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
draw bb withpen pencircle scaled 1pt withcolor .625red ;
draw origin withpen pencircle scaled 5pt withcolor .625yellow ;

% 填充(在路径内)
pickup pencircle scaled .5cm ;
fill unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
draw bb withpen pencircle scaled 1pt withcolor .625red ;
draw origin withpen pencircle scaled 5pt withcolor .625yellow ;

% 填绘
pickup pencircle scaled .5cm ;
filldraw unitsquare xscaled 8cm yscaled 1cm withcolor .625white ;
path bb ; bboxmargin := 0pt ; bb := bbox currentpicture ;
draw bb withpen pencircle scaled 1pt withcolor .625red ;
draw origin withpen pencircle scaled 5pt withcolor .625yellow ;

解散字模#

调试#

读写文件#

导出通用文件#

prologues := 2 ;

#

嵌入图形#

开始#

外部图形#

  • \externalfigure[graphic.123][width=4cm]
  • useexternalfigure
    • \useexternalfigure[pentastar][star.803][height=4cm]
    • \useexternalfigure[octostar] [star.804][pentastar]
    • \placefigure{A five||point star drawn by \METAPOST.}{\externalfigure[pentastar]}

整合图形#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
% 直接使用
\startMPcode
fill fullcircle scaled 200pt withcolor .625white ;
\stopMPcode

% 先定义图形,再使用
\startuseMPgraphic{name}
fill fullcircle scaled 200pt withcolor .625yellow ;
\stopuseMPgraphic
% 每次使用都会重新计算一遍,因此可以改变属性
\useMPgraphic{name}

% 可重用图形,不会每次使用都计算一遍,节省计算资源
\startreusableMPgraphic{name}
fill fullcircle scaled 200pt withcolor .625yellow;
\stopreusableMPgraphic
\reuseMPgraphic{name}

% unique图形,每次使用都会重新计算
\startuniqueMPgraphic{name}
path p ; p := unitsquare
xscaled OverlayWidth yscaled OverlayHeight ;
fill p withcolor .625yellow ;
draw p withcolor .625red ;
\stopuniqueMPgraphic
\defineoverlay[my graphic][\uniqueMPgraphic{name}]
\button[background=my graphic,frame=off]{Go Home}[firstpage]

% 运行时图形,比如mylogos.mp,每次生成图形,再插入
\startMPrun
input mylogos ;
\stopMPrun
% 或指定解释命令和文件路径
\startMPrun{extrafun::mydemo}
input mfun-mrun-demo.mp ;
\stopMPrun

不用CONTEXT,只用METAFUN#

1
2
3
4
\startMPpage
% Your mp code goes here. You can use the textext
% macro as discussed later to deal with typeset text.
\stopMPpage

Lua#

导语#

基础#

metafun向tex输入流馈入字符串:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
% 
numeric n ; n := scantokens("123.456") ;

% 
numeric n ; n := runscript("return '123.456'") ;

% 
local function scriptrunner(code)
    local f = loadstring(code)
    if f then
        return tostring(f())
    else
        return ""
    end
end
local m = mplib.new {
    ...
    run_script = scriptrunner,
    ...
}

辅助函数#

CONTEXT的方式:

1
2
numeric n ; n := lua("mp.print(12.34567)") ;
draw textext(n) xsized 4cm withcolor darkred ;

字符串#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
draw
textext("This will print \quotation{Hi} in the console!")
xsized TextWidth
withcolor "darkblue" ;
% 运行lua脚本
runscript("print('Hi')");

% 给mp返回字符串
string s ;
s := runscript("mp.quoted('This will return a string!')") ;
draw textext(s)
    xsized TextWidth
    withcolor "darkgreen" ;

数字#

runscript 10000;

CONTEXT/METAFUN辅助函数#

1
2
draw lua.mp.foo(0,2,(3,4)) ; % mp是给CONTEXT用的
fill lua.MP.foo(0,2,(3,4)) ; % MP是给用户使用的

在lua段,被映射到相应的函数:

1
2
3
4
5
6
function mp.foo(n,m,p)
-- do something
end
function MP.foo(n,m,p)
-- do something
end
1
2
3
4
5
6
7
8
numeric n ; n := lua("mp.print(12.34567)") ;
draw textext(n) xsized 4cm withcolor darkred ;

numeric n ; n := lua("mp.print(1) mp.print('+') mp.print(2)") ;
draw textext(n) xsized 1cm withcolor darkred ;
% 等价于
numeric n ; n := lua("mp.print(1,'+',2)") ;
draw textext(n) xsized 1cm withcolor darkred ;

从lua打印到mp(传递数据)#

所打印的字符串即为合法的mp代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
fill fullcircle scaled runscript("mp.print('3cm')") withcolor "darkred" ;
fill fullcircle scaled runscript("mp.print.print('2cm')") withcolor "darkgreen" ;
fill fullcircle scaled runscript("mp.aux.print('1cm')") withcolor "darkblue" ;

% 打印路径
local t1 = { {0,0}, {1,0}, {1,1}, {0,1} }
local t2 = { {0,0}, {1,0}, {1,1}, {0,1}, cycle = true }
mp.print.path(t1)
mp.print.path(t1,nil,true)
mp.print.path(t1,true,true)
mp.print.path(t1,false)
mp.print.path(t1,false,true)
mp.print.path(ts,false)
mp.print.path(t1,"...",true)
mp.print.path(t1,"..",true)
mp.print.path(t2,"..")

Direct值#

与打印机近似的注入器:

1
2
3
function MP.MyFunction()
    mp.inject.string("This is just a string.")
end

包括: boolean, cmykcolor, color, integer, number, numeric, pair, path, quadruplet, string, transform, triplet and whatever (kind of automatic)

寄存器#

特殊辅助函数#

哈希

模式

1
2
3
4
5
6
\enablemode[weird]
\startMPcode
    fill fullsquare xyscaled (TextWidth,5mm)
    withcolor if texmode("weird") : "darkblue" else : "darkgreen" fi ;
\stopMPcode
\disablemode[weird]

定位

TeX数量

UTF8

1
2
3
4
5
6
string s ; s := "ÀÁÂÃÄÅàáâãäå" ;
draw textext(s) shifted ( 0cm,0) withcolor "darkyellow" ;
draw textext(utfnum("Â")) shifted ( 3cm,0) withcolor "darkmagenta" ;
draw textext(utflen(s)) shifted ( 6cm,0) withcolor "darkcyan" ;
draw textext(utfsub(s,3,4)) shifted ( 9cm,0) withcolor "darkblue" ;
draw textext(utfsub(s,6)) shifted (12cm,0) withcolor "darkred" ;

使用变量#

#

CONTEXT辅助函数#

  • mp.string string passed as it is but with percent, double quote and newline escaped
  • mp.boolean boolean the true or false primitives
  • mp.integer number an integer
  • mp.number number a float
  • mp.numeric number a float (same as previous)
  • mp.points number a scaled numeric with pt unit
  • mp.pair numbers or table a pair (x,y) or (x,x)
  • mp.pairpoints numbers or table idem but with scaled numbers and a pt unit
  • mp.triplet numbers or table a rgb triplet (r,g,b)
  • mp.tripletpoints numbers or table idem but with scaled numbers and a pt unit
  • mp.quadruple numbers or table a cmyk quadruple (c,m,y,k)
  • mp.quadruplepoints numbers or table idem but with scaled numbers and a pt unit
  • mp.color numbers or table a numeric, triplet or quadruple
  • mp.transform numbers or table a six element transform
  • mp.print whatever the normal semi-intelligent printer
    • mp.print.path
  • mp.inject
    • mp.inject.path
  • mp.fprint format, whatever the normal semi-intelligent printer using a format
  • mp.vprint variable the normal semi-intelligent printer with escaped percents, quotes and newlines
  • mp.quoted string a valid string surrounded by quotes with an optional first format specifier
  • mp.print(...) returns one or more values
  • mp.pair(x,y) pair(t) returns a proper pair
  • mp.triplet(x,y,z) triplet(t) returns an RGB color
  • mp.quadruple(w,x,y,z) quadruple(t) returns an CMYK color
  • mp.format(fmt,...) returns a formatted string
  • mp.quoted(fmt,...) quoted(s) returns a (formatted) quoted string
  • mp.path(t[,connect][,close]) returns a connected (closed) path
  • mp.get.numeric(name) gets a numeric from METAPOST
  • mp.get.boolean(name) gets a boolean from METAPOST
  • mp.get.string(name) gets a string from METAPOST

METAPOST向CONTEXT/lua传递参数#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
\startMPcalculation
passvariable("version","1.0") ;
passvariable("number",123) ;
passvariable("string","whatever") ;
passvariable("point",(1.5,2.8)) ;
passvariable("triplet",(1/1,1/2,1/3)) ;
passvariable("quad",(1.1,2.2,3.3,4.4)) ;
passvariable("boolean",false) ;
passvariable("path",fullcircle scaled 1cm) ;
path p[] ; p[1] := fullcircle ; p[2] := fullsquare ;
passarrayvariable("list",p,1,2,1) ; % first last step
\stopMPcalculation

% 或在MP代码中
\startMPcode
path p ; p := fullcircle xyscaled (10cm,2cm) ;
path b ; b := boundingbox p ;
startpassingvariable("mypath")
    passvariable("points",p) ;
    startpassingvariable("metadata")
        passvariable("boundingbox",boundingbox p) ;
    stoppassingvariable ;
stoppassingvariable ;
fill p withcolor .625red ;
draw b withcolor .625yellow ;
\stopMPcode

lua端通过表metapost.variables使用

1
2
3
\startluacode
context.tocontext(metapost.variables)
\stopluacode

tex用法:

\MPruntab{quad}{3}

跟踪参数:

\enabletrackers[metapost.variables]

Asymptote#

新一代矢量绘图语言兼编程语言,受到MetaPost启发,使用类似C++的更简洁的编程语法和IEEE浮点数。可生成高质量的PostScript, OpenGL, PDF, SVG, WebGL, V3D, and PRC矢量图形。

使用filter模块部分整合到ConTeXt中(与标签有关的字体、颜色、宏等无法整合):

评论