Metafont 中的尖角?

Metafont 中的尖角?

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.nibfine.nib、到底是什么rule.nib
  • 为什么有些.nibs 需要这样的作业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的副本——这是一支专用笔,用来绘制数学符号,如、和。pencirclerule_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@#lx@#ry@#y@#ly@#r,其中@#替换为您使用的任何后缀。
因此,如果您调用pos1(b, d)宏,将定义x1x1lx1ry1y1ly1r

或者更确切地说它将定义一些有用的关系它们之间;特别是这六个变量可以组合起来定义三个点:(x1l, y1l)(x1r, y1r)(x1, y1)——通过通常的普通 MF 约定将 定义z@#(x@#, y@#),现在您可以将这三个点称为z1lz1rz1,并且它们将被定义为正好是和z1之间的 1/2并且和之间的距离为,旋转角度为。z1lz1rz1lz1rbd

z1请注意,此时您仍然需要定义位置——pos所做的一切只是确定放置的位置z1lz1r时间z1......

你可能会问,这一切的意义何在?答案是设置宏stroke...

stroke

stroke中的宏定义cmbase.mf一开始比较难理解,但最终结果是它将非循环路径变成z1 -- z2了可以填充的循环框路径。

为了使其工作,您必须为每个点定义额外的lr变量。这就是它的pos@#作用。因此,如果您已经调用pos1pos2stroke z1e -- z2e则将返回循环路径

z1l -- z2l -- z2r -- z1r -- cycle

你可以将其传递给fill。因此,要回答 OP 的问题,区别在于

  • fill z1e -- z2e;是一个错误,你的意思可能是draw z1 -- z2

  • fill stroke z1e -- z2ez1l -- z2l -- z2r -- z1r -- cycle只要lr后缀定义正确,就会填充该框。

答案

经历了这一切之后,我思考“哪里错了?”这个问题的答案是,crisp.nib太小了,以至于你在最后做的时候看不到线draw z1--z2。宽度可能已经四舍五入为等于零的整数像素。所以既然你已经设置了pos1pos2你可以尝试这样做fill stroke z1e--z2e

相关内容