Computer Modern 斜线的源代码是:
cmchar "Virgule (slash)";
beginchar("/",9u#,body_height#,paren_depth#);
italcorr body_height#*slant-.5u#;
adjust_fit(0,0); pickup rule.nib;
rt x1=hround(w-u)+eps; top y1=h+eps;
lft x2=hround u-eps; bot y2=-d-eps;
draw z1--z2; % diagonal
penlabels(1,2); endchar;
角是圆的。我想要尖角(但厚度相同);斜线应该是平行四边形。我发现可以crisp.nib
画出尖角,但必须与一起使用pos1 ... pos2
。所以我尝试了:
cmchar "Virgule (slash)";
beginchar("/",9u#,body_height#,paren_depth#);
italcorr body_height#*slant-.5u#;
adjust_fit(0,0); pickup crisp.nib;
pos1(rule_thickness+2eps,-45); pos2(rule_thickness+2eps,-45);
rt x1=hround(w-u)+eps; top y1=h+eps;
lft x2=hround u-eps; bot y2=-d-eps;
draw z1--z2; % diagonal
penlabels(1,2); endchar;
但是斜线消失了,现在它只是一条直线。出了什么问题?
有一些 Metafont 教程,但我没有找到其他一些问题的答案:
crisp.nib
、fine.nib
、到底是什么rule.nib
?- 为什么有些
.nib
s 需要这样的作业pos1(...); pos2(...), ...
,而其他的则不需要?哪些需要这样的作业? fill
和有什么区别fill stroke
?- 确切的论点是什么
pos1(...)
以及如何找出正确的值?
感谢您的帮助。
答案1
我无法立即回答“哪里出了问题?”这个问题,但你可以在书中找到许多回答其他问题的细节E 卷:计算机现代字体,D.Knuth,1986 年,特别是解释的附录cmbase.mf
。如果你无法阅读本书,你可以通过阅读源代码来了解它的内容,你可以在本地 TeX 树中找到它..texmf-dist/fonts/source/public/cm/cmbase.mf
笔尖
这些.nib
变量都是内置pencircle
笔的副本,按有用的尺寸缩放:
crisp.nib
缩放到crisp
参数的值,该参数设置衬线角的直径tiny.nib
缩放至tiny
,设置圆角的直径fine.nib
缩放至fine
,设置锐角的直径
这是绘制Computer Modern时使用的三种主要笔。roman、italic、bold等的参数设置不同。
还有,它也是缩放到rule.nib
的副本——这是一支专用笔,用来绘制数学符号,如、和。pencircle
rule_thickness
+
/
=
宏pos()
该pos
宏是纯 MF 中宏的泛化penpos
。其定义如下:
newinternal currentbreadth;
vardef pos@#(expr b,d) =
if known b: if b<=currentbreadth: errmessage "bad pos"; fi fi
(x@#r-x@#l,y@#r-y@#l)=(b-currentbreadth,0) rotated d;
x@#=.5(x@#l+x@#r); y@#=.5(y@#l+y@#r) enddef;
参数是后缀@#
和两个表达式b
= 宽度和d
= 旋转。它使用一个全局内部变量来currentbreadth
跟踪当前笔的宽度。
如果您取消选择宏,您将看到它创建了两个链接的三个变量集:x@#
、x@#l
、x@#r
和y@#
、y@#l
、y@#r
,其中@#
替换为您使用的任何后缀。
因此,如果您调用pos1(b, d)
宏,将定义x1
、x1l
、x1r
、y1
、y1l
和y1r
。
或者更确切地说它将定义一些有用的关系它们之间;特别是这六个变量可以组合起来定义三个点:(x1l, y1l)
、(x1r, y1r)
和(x1, y1)
——通过通常的普通 MF 约定将 定义z@#
为(x@#, y@#)
,现在您可以将这三个点称为z1l
、z1r
和z1
,并且它们将被定义为正好是和z1
之间的 1/2并且和之间的距离为,旋转角度为。z1l
z1r
z1l
z1r
b
d
z1
请注意,此时您仍然需要定义位置——pos
所做的一切只是确定放置的位置z1l
和z1r
时间z1
......
你可能会问,这一切的意义何在?答案是设置宏stroke
...
宏stroke
stroke
中的宏定义cmbase.mf
一开始比较难理解,但最终结果是它将非循环路径变成z1 -- z2
了可以填充的循环框路径。
为了使其工作,您必须为每个点定义额外的l
和r
变量。这就是它的pos@#
作用。因此,如果您已经调用pos1
和pos2
,stroke z1e -- z2e
则将返回循环路径
z1l -- z2l -- z2r -- z1r -- cycle
你可以将其传递给fill
。因此,要回答 OP 的问题,区别在于
fill z1e -- z2e;
是一个错误,你的意思可能是draw z1 -- z2
。fill stroke z1e -- z2e
z1l -- z2l -- z2r -- z1r -- cycle
只要l
和r
后缀定义正确,就会填充该框。
答案
经历了这一切之后,我思考“哪里错了?”这个问题的答案是,crisp.nib
太小了,以至于你在最后做的时候看不到线draw z1--z2
。宽度可能已经四舍五入为等于零的整数像素。所以既然你已经设置了pos1
,pos2
你可以尝试这样做fill stroke z1e--z2e
。