100 如何高效优雅地从mathabx宏包中偷出来\measuredangle的符号?

发布于 2025-07-25 15:46:10

背景介绍

这个链接中有一些「偷」符号的信息。但是似乎没有介绍如何寻找cmex这样的字体族名对「偷」的思路介绍,所以再开一个问题。

texdoc comprehensive得到的symbols-a4.pdf中有:
image.png

为了让代码尽可能「轻」,减少与其他宏包如amssymb的定义重复,我想把这个符号「偷出来」:

我使用了如下的思路:

CTAN下载mathabx包的.zip文件,文件的目录结构如下:

image.png

./texinput/mathabx.dcl中:

% line 202
\DeclareMathSymbol{\measuredangle} {0}{mathb}{"3E}

同时 一通乱点乱搜 可以找到在./texinput/mathabx.sty中:

% line 51
\mathabx@mathb
\DeclareFontFamily{U}{mathb}{\hyphenchar\font45}
\DeclareFontShape{U}{mathb}{m}{n}{
      <5> <6> <7> <8> <9> <10> gen * mathb
      <10.95> mathb10 <12> <14.4> <17.28> <20.74> <24.88> mathb12
      }{}
\DeclareSymbolFont{mathb}{U}{mathb}{m}{n}
\DeclareFontSubstitution{U}{mathb}{m}{n}
\end@mathabx

然后或许得到了一个可行的MWE:

\documentclass{article}
\usepackage{amsmath}
\usepackage{amssymb}%必须放前面...
\DeclareFontFamily{U}{mathb}{\hyphenchar\font45}
\DeclareFontShape{U}{mathb}{m}{n}{
      <5> <6> <7> <8> <9> <10> gen * mathb
      <10.95> mathb10 <12> <14.4> <17.28> <20.74> <24.88> mathb12
      }{}
\DeclareSymbolFont{mathb}{U}{mathb}{m}{n}
\DeclareFontSubstitution{U}{mathb}{m}{n}
\DeclareMathSymbol{\measuredangle} {0}{mathb}{"3E}
\begin{document}

\[ a \measuredangle b \quad \mathbb{E}(X) \]

\end{document}

image.png

问题:

  1. 如何找到并熟悉常见的如cmexAMSa类似的“字体族名”?
  2. 上面的操作是正确的吗?一次正确的优雅的高效的的「偷字符操作」是不是总是要找到宏包中对字符定义的这一段?\DeclareFontFamily\DeclareFontShape\DeclareSymbolFont\DeclareFontSubstitution\DeclareMathSymbol一个不能少?
\DeclareFontFamily{U}{mathb}{\hyphenchar\font45}
\DeclareFontShape{U}{mathb}{m}{n}{
      <5> <6> <7> <8> <9> <10> gen * mathb
      <10.95> mathb10 <12> <14.4> <17.28> <20.74> <24.88> mathb12
      }{}
\DeclareSymbolFont{mathb}{U}{mathb}{m}{n}
\DeclareMathSymbol{\measuredangle} {0}{mathb}{"3E}
\DeclareFontSubstitution{U}{mathb}{m}{n}

Side-Notes: 基于unicode-math是否有XeTeX的(或许更便捷的)方案来偷mathabx中的\measuredangle呢?

查看更多

关注者
0
被浏览
231
2 个回答
Thallo
Thallo 2025-07-26
这家伙不懒,但还是什么也没写
Eureka
Eureka 2025-07-30
这家伙很懒,什么也没写!

\measuredangle 对应 glyph 的具体定义在文件 mathsymb.mf 的 852 行,

%%% !!!
beginchar(measured_angle,12u#+2appr#,asc_height#,asc_depth#);
  "Measured angle sign";
  pickup tiny.nib;
  rt x1l=w-appr; lft x2l=appr; rt x3r=w-appr-hround 1.5u;
  bot y1l=bot y2l=0; top y3l=h+eps; pos1(rth,90);
  (x3r-x3l,y3l-y3r)=d_problem(z2l,y3l,x3r,rth-tiny);
  y2r=y1r; z2r-z3r=whatever*(z2l-z3l);
  filldraw stroke z1e--z2e--z3e;
  %
  numeric a;
  y2l=y5r; rt x5r=hround max(0.6[Appr,w-Appr]+0.5rth,x2l+0.5(h+d))+eps;
  pos5(rth,0);
  a=x5r-x2l; 0.5 y4=-d+eps; 0.5(x4-x2l)=a+-+min((0.5(y4-y2l)),a);
  0.5(z6-z2l)=a*dir min((angle(z3l-z2l)-angle(z4-z2l)),90);
  numeric t[];
  tmp_path:=halfcircle rotated -90 scaled 2(x5r-x2r) shifted z2r;
  tmpp_path:=reverse(halfcircle rotated -90 scaled 2(x5l-x2r) shifted z2r);
  t1=xpart(tmp_path intersectiontimes (z2l..z4));
  t2=xpart(tmp_path intersectiontimes (z2l..z6));
  z4r=point t1 of tmp_path; z6r=point t2 of tmp_path;
  t3=xpart(tmpp_path intersectiontimes (z2l..z6));
  t4=xpart(tmpp_path intersectiontimes (z2l..z4));
  z4l=point t4 of tmpp_path; z6l=point t3 of tmpp_path;
  filldraw subpath (t1,t2) of tmp_path
  --subpath (t3,t4) of tmpp_path--cycle;
  penlabels(1,2,3,4,5,6);
endchar;

似乎是需要用到 metatype1 ? 待续 ...


再次更新, 首先把 mathprmt.mf 复制到一个单独的文件夹出来(方便后期更改), 然后再把上述 measured_angle 的定义摘抄出来, 形成如下的文件:

%%%%%%%%%%%%%%          Preamble        %%%%%%%%%%%%%%
% 1. variables like: 'appr#' are inside it:
input mathprmt;  % load library 'mathbase.mf'

% 2. mode/math setup and function 'd_problem()' in 'mathsymb.mf'
mode_setup;
math_setup;
measured_angle := hex"3E";  % this variable must be known !!!
vardef d_problem(expr origin,top_lim,side_lim,breadth)=
  save a,b,c;
  a=abs((side_lim-xpart origin)/(top_lim-ypart origin));
  b=abs(breadth/(top_lim-ypart origin));
  begingroup
    vardef f(expr c)=
      (1+a**2-2a*b*c+(b*c)**2)*(c**2)<1
    enddef;
    c=solve f(0,breadth);
  endgroup;
  breadth*(c,1+-+c)
enddef;


%%%%%%%%%%%         Main doc        %%%%%%%%%%%%%%
beginchar(measured_angle,12u#+2appr#,asc_height#,asc_depth#);
  "Measured angle sign";
  pickup tiny.nib;
  rt x1l=w-appr; lft x2l=appr; rt x3r=w-appr-hround 1.5u;
  bot y1l=bot y2l=0; top y3l=h+eps; pos1(rth,90);
  (x3r-x3l,y3l-y3r)=d_problem(z2l,y3l,x3r,rth-tiny);
  y2r=y1r; z2r-z3r=whatever*(z2l-z3l);
  filldraw stroke z1e--z2e--z3e;
  %
  numeric a;
  y2l=y5r; rt x5r=hround max(0.6[Appr,w-Appr]+0.5rth,x2l+0.5(h+d))+eps;
  pos5(rth,0);
  a=x5r-x2l; 0.5 y4=-d+eps; 0.5(x4-x2l)=a+-+min((0.5(y4-y2l)),a);
  0.5(z6-z2l)=a*dir min((angle(z3l-z2l)-angle(z4-z2l)),90);
  numeric t[];
  tmp_path:=halfcircle rotated -90 scaled 2(x5r-x2r) shifted z2r;
  tmpp_path:=reverse(halfcircle rotated -90 scaled 2(x5l-x2r) shifted z2r);
  t1=xpart(tmp_path intersectiontimes (z2l..z4));
  t2=xpart(tmp_path intersectiontimes (z2l..z6));
  z4r=point t1 of tmp_path; z6r=point t2 of tmp_path;
  t3=xpart(tmpp_path intersectiontimes (z2l..z6));
  t4=xpart(tmpp_path intersectiontimes (z2l..z4));
  z4l=point t4 of tmpp_path; z6l=point t3 of tmpp_path;
  filldraw subpath (t1,t2) of tmp_path
  --subpath (t3,t4) of tmpp_path--cycle;
  penlabels(1,2,3,4,5,6);
endchar;
end


%%%% Compile it by %%%%%%
% mf measure_angle.mf
% gftodvi measure_angle.2602gf
% dvips measure_angle.dvi
% ps2pdf measure_angle.ps

依次使用如下的命令进行编译:

mf measure_angle.mf
gftodvi measure_angle.2602gf
dvips measure_angle.dvi
ps2pdf measure_angle.ps

然后你就可以看到 measure_angle.pdf 生成了, 截图如下:
image.png

目前想要在 TeX 中使用该符号还有两个问题:

  • 还需要生成对应的 tfm 文件, 或许还需要 .pk 文件;
  • 点阵字体不行, 可能需要用一点 metatype1 里面的东西;
  • 待续 ...

下面讲解如何在 LaTeX 中使用这个符号. 首先在生成对应的 .tfm 文件(TeX Font Metric), 使用如下命令:

mf '\mode=ljfour; input measure_angle.mf'

然后你会看到类似如下的日志输出:

$ mf '\mode=ljfour; input measure_angle.mf'
This is METAFONT, Version 2.71828182 (TeX Live 2026/dev/Arch Linux) (preloaded base=mf)
(measure_angle.mf (mathprmt.mf (mathbase.mf)) [62] )
Font metrics written on measure_angle.tfm.
Output written on measure_angle.600gf (1 character, 196 bytes).
Transcript written on measure_angle.log.

我们生成了 measure_angle.tfmmeasure_angle.600gf 两个文件(也许你生成的后一个文件中的数字不是 600, 或者干脆就没有 600 这个字样). 现在你就需要把上面的 *gf 文件转化为 .pk 文件(Packed Raster - 点阵), 使用如下的命令:

gftopk measure_angle.600gf measure_angle.600pk
注意: 如果你上一步生成的是 measure_angle.600gf 这种格式的文件, 那么上述的 .600pk 中的 600 则不能省略 !

随后在当前文件夹就会生成一个名为 measure_angle.600pk 的文件, 有了:

  • measure_angle.600pk
  • measure_angle.tfm

两个文件之后我们就可以在 LaTeX 中使用这个符号了, 使用方法如下:

\documentclass{article}

\newfont{\symbolangle}{measure_angle}
\newcommand{\measureangle}{{\symbolangle\char"3E}} % slot 编号请参见 measure_angle.mf 文件 
\begin{document}
A new symbol by MetaFont: \measureangle $A = 45^\circ$
\end{document}

其实也可以直接使用 *.mf 文件, 那么你的当前工作路径下必须要有:

  • mathbase.mf
  • mathprmt.mf
  • measure_angle.mf

三个文件(并不是那么的方便). 在第一次编译时,会自动生成对应的 tfmpk 文件, 之后编译时就不需要了. 第一次的编译日志大概长这样:

This is pdfTeX, Version 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
(/usr/share/texmf-dist/tex/latex/base/article.cls
Document Class: article 2024/06/29 v1.4n Standard LaTeX document class
(/usr/share/texmf-dist/tex/latex/base/size10.clo))
kpathsea: Running mktextfm measure_angle
mktextfm: Running mf-nowin -progname=mf \mode:=ljfour; mag:=1; ; nonstopmode; input measure_angle
This is METAFONT, Version 2.71828182 (TeX Live 2026/dev/Arch Linux) (preloaded base=mf)

(/home/<name>/Document/Temp/tex_program/mathabx/test/measure_angle.mf
(/home/<name>/Document/Temp/tex_program/mathabx/test/mathprmt.mf
(/home/<name>/Document/Temp/tex_program/mathabx/test/mathbase.mf)) [62] )
Font metrics written on measure_angle.tfm.
Output written on measure_angle.600gf (1 character, 196 bytes).
Transcript written on measure_angle.log.
mktextfm: /home/<name>/Document/Temp/tex_program/mathabx/test/measure_angle.tfm: successfully generated.

(/usr/share/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def) (./test.aux)
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./test.aux) ) <./measur
e_angle.600pk></usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb><
/usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb>
Output written on test.pdf (1 page, 23647 bytes).
Transcript written on test.log.

第二次的编译日志大概长这样:

This is pdfTeX, Version 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
(/usr/share/texmf-dist/tex/latex/base/article.cls
Document Class: article 2024/06/29 v1.4n Standard LaTeX document class
(/usr/share/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def) (./test.aux)
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./test.aux) )</usr/shar
e/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texmf-dist/f
onts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texmf-dist/fonts/type1/publ
ic/amsfonts/cm/cmsy7.pfb>
Output written on test.pdf (1 page, 31385 bytes).
Transcript written on test.log.

编译结果如下:
image.png

但是上面的符号在 pdf 里面看起来是比较奇怪的(但是它在纸张上的打印效果是很棒的), 因为它是点阵字体,想要它看起来光滑一点, 没有毛边,那么就需要去自己去修改

  • pdftex.map 文件, 如果你是用的是 pdfTeX 引擎
  • 或者是 xdvipdfm 的配置文件, 如果你使用的是 XeTeX 引擎.

上面其实还有一个问题 -- \measureangle 不能嵌套在公式环境中, 下次解决.

所以这次就写到这里了, 待续 ...

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览