我有时发现\widetilde
重音符号的位置比它所应用的数学字母高太多。例如:
在我看来,第一个波浪线似乎位于两条线之间;它没有在视觉上与“B”相连。正如第二个“B”波浪线所示,我确实设法制作了一个降低的版本\widetilde
,但这是一个丑陋的黑客使用\textcolor
:
\rlap{\raisebox{-0.1ex}{$\widetilde{B}$}}
\rlap{\smash{\textcolor{white}{\rule[-1ex]{2em}{2.7ex}}}}
B
我在这里做的是:我降低所有的 \widetilde{B}
然后我用一些(手动调整的)白框擦除“B”,最后排版输出中看到的“B”。当然,我把它包装在某个宏中,但这个宏不适用于“m”这样的小字母,这是由于白框造成的。
更直接的尝试
\rlap{\raisebox{-0.1ex}{$\widetilde{\phantom{B}}$}}B
输出显示不起作用:波浪线太靠左了。原因是 TeX 对单个字符的重音符号的处理方式不同,使用\skewchar
字体的\phantom{B}
不是单个字符。此外,在版本中\tilde B
我发现波浪号太小了:。
我的解决方案的一个问题是,当我在 Yap 中查看 dvi 文件时,它无法正确呈现。有谁知道更好的解决方案来降低\widetilde
吗?
编辑:
TH 的第一个解决方案效果相当好。它唯一的缺点是它不会降低\widetilde
过小的字母,例如“m”。然而,这不是什么大问题,因为在这种情况下,波浪号看起来不像是位于两行之间。我想出了一个解决方案,它确实降低了过\widetilde
小的“m”,但存在其他重大问题。TH 的(相当复杂的)第二个解决方案解决了大部分这些问题。干得好!
答案1
实现1
此代码会根据其参数更改重音字体的 x 高度。它应该相当可靠。与其将高度缩放 1.3,不如简单地为其添加一个固定值。由于 TeX 计算重音高度的方式,重音存在最小高度,因此这往往对小写字母没有明显的影响。
\makeatletter
\newcommand*\wt[1]{\mathpalette\wthelper{#1}}
\newcommand*\wthelper[2]{%
\hbox{\dimen@\accentfontxheight#1%
\accentfontxheight#11.3\dimen@
$\m@th#1\widetilde{#2}$%
\accentfontxheight#1\dimen@
}%
}
\newcommand*\accentfontxheight[1]{%
\fontdimen5\ifx#1\displaystyle
\textfont
\else\ifx#1\textstyle
\textfont
\else\ifx#1\scriptstyle
\scriptfont
\else
\scriptscriptfont
\fi\fi\fi3
}
\makeatother
实施2
本文件试图复制第 12 条和附录 G 中第 16-18 条的相关部分。TeXbook用于排版数学重音。
关于实现的一些说明:我不知道如何计算后继者,因此我用盒子代替是应该只是重音符号和斜体校正$\widetilde{\hphantom{...}}$
。因此,波浪符号应该已经移动了一半(瓦+宽度(是)). 从tex.web
,框的移位量是由给出,
shift_amount(y):=s+half(w-width(y));
因此足以计算字距s并向右移动该量。
下面的代码包含3个主要部分。
它所做的第一件事是尝试解析将
\wt
作为 Acc 原子核出现的参数。这是极其易碎。如果参数扩展为除\relax
、\bgroup
、\egroup
、\begingroup
、\endgroup
、\fam
、\
(控制空间)、\char
(未测试)、\mathchar
(未测试)、\mathcode
(未测试)、字母或符号之外的任何基元,它将把核心视为非单个字符,即使它实际上是单个字符。如果存在未知的控制序列,例如\let\unknown\foo
,它将失败并出现神秘错误,因为它无法扩展\unknown
。需要付出一些努力来检查字体的变化。如果
\wt@checknucleus
宏确定我们要伪造的 Acc 原子的原子核只是一个字符,它会存储并通过设置为来\mathcode
记录这一事实。(我想代码的第三部分可以只检查保存的数学代码。)\ifwt@nucleussingle
\iftrue
完成后
\wt@checknucleus
,它会向前扫描以查找_
和^
。如果这些隐藏在宏中,它将找不到它们!所有下标和上标都会保存下来,以便稍后在规则 12 或规则 18 中处理。最后,
\wt@choice
使用\mathchoice
这 4 种样式中的每一种来排版公式\wt@applyrules
,然后选择合适的样式。\wt@applyrules
包含来自的相关规则TeXbook作为注释,后面跟着一些尝试应用规则的代码。
代码并不完美。请参阅本答案底部的测试输出。此外,它还丢失了拥挤因为 pdfTeX 没有提供测试它的方法。它确实在规则 12 要求的地方执行了适当的压缩。
\makeatletter
\newif\ifwt@nucleussingle
\newif\ifwt@sub
\newif\ifwt@sup
\newtoks\wt@nucleus
\newtoks\wt@sub
\newtoks\wt@sup
\newcount\wt@nucleusmathcode
\newcount\wt@fam
\newdimen\wt@s
\newdimen\wt@delta
\DeclareRobustCommand*\wt[1]{%
\begingroup
\wt@nucleus{#1}%
\wt@checknucleus%
\wt@subfalse
\wt@supfalse
\futurelet\wt@temp\wt@parse
}
\def\wt@checknucleus{%
\begingroup
\wt@nucleussinglefalse
\setbox\z@\hbox{$\the\wt@nucleus
\def\use@mathgroup##1##2{\relax\math@bgroup
\mathgroup##2\relax\math@egroup}%
\expandafter\xdef\expandafter\wt@gtemp
\expandafter{\the\wt@nucleus}$}%
\expandafter\wt@checktoken\wt@gtemp\wt@sentinel
\endgroup
\wt@gtemp
}
\def\wt@sentinel{\wt@sentinel}
\def\wt@checktoken#1{%
\let\wt@temp\wt@checktoken
\ifx#1\relax
\else\ifx#1\bgroup
\bgroup
\else\ifx#1\egroup
\egroup
\else\ifx#1\begingroup
\begingroup
\else\ifx#1\endgroup
\endgroup
\else\ifx#1\fam
\let\wt@temp\fam
\afterassignment\wt@checktoken
\else\ifx#1 \else\ifx#1\wt@sentinel
\let\wt@temp\relax
\else\ifx#1\@sptoken
\else\ifcat#1a%
\wt@checksingle{\mathcode`#1}%
\else\ifcat#1/%
\wt@checksingle{\mathcode`#1}%
\else\ifx#1\char
\let\wt@temp\count@
\afterassignment\wt@checkchar
\else\ifx#1\mathchar
\let\wt@temp\count@
\afterassignment\wt@checkmathchar
\else\ifx#1\mathcode
\let\wt@temp\mathcode
\afterassignment\wt@checktoken
\else
\global\let\wt@gtemp\wt@nucleussinglefalse
\wt@nucleussingletrue % Not really true...
% In principle, this could handle every primitive.
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
\wt@temp
}
\def\wt@checkchar{%
\wt@checksingle{\mathcode\count@}%
\wt@checktoken
}
\def\wt@checkmathchar{%
\wt@checksingle{\count@}%
\wt@checktoken
}
\def\wt@checksingle#1{%
\ifwt@nucleussingle
\global\let\wt@gtemp\wt@nucleussinglefalse
\else
\xdef\wt@gtemp{%
\noexpand\wt@nucleussingletrue
\wt@fam\the\fam\relax
\wt@nucleusmathcode\the#1\relax
}%
\wt@nucleussingletrue
\fi
}
\def\wt@parse{%
\let\wt@next\wt@choice
\ifdefmacro{\wt@temp}{}%
{%
\ifcat_\wt@temp
\ifwt@sub\else
\let\wt@next\wt@parsesub
\fi
\else\ifcat^\wt@temp
\ifwt@sup\else
\let\wt@next\wt@parsesup
\fi
\else\ifcat\@sptoken\wt@temp
\def\wt@next##1{\futurelet\wt@temp\wt@parse}%
\fi\fi\fi
}%
\wt@next
}
\def\wt@parsesub#1#2{%
\wt@sub{#2}%
\wt@subtrue
\futurelet\wt@temp\wt@parse
}
\def\wt@parsesup#1#2{%
\wt@sup{#2}%
\wt@suptrue
\futurelet\wt@temp\wt@parse
}
\def\wt@choice{%
\mathchoice{\wt@applyrules\displaystyle\textfont}%
{\wt@applyrules\textstyle\textfont}%
{\wt@applyrules\scriptstyle\scriptfont}%
{\wt@applyrules\scriptscriptstyle\scriptscriptfont}%
\endgroup
}
\def\wt@applyrules#1#2{%
% The following block comments are quotes from Knuth's The
% TeXbook. My notes appear [in brackets].
%
% Rule 12:
% If the current item is an Acc atom (from \mathaccent) [this
% is what we're constructing], just go to Rule 16 if the
% accent character doesn't exist in the current size [ignoring
% this]. Otherwise set box x to the nucleus in style C', and
% set u to the width of this box.
% [We don't need u.]
\setbox\z@\hbox{$\m@th\cramped[#1]{\the\wt@nucleus}$}%
% If the nucleus is not a single character, let s = 0;
% otherwise set s to the kern amount for the nucleus followed
% by the \skewchar of its font
\ifwt@nucleussingle
\count@\wt@nucleusmathcode
\divide\count@\@cclvi
\@tempcnta\count@
\divide\@tempcnta8
\multiply\@tempcnta8
\advance\count@-\@tempcnta
\ifnum\@tempcnta="70
\ifnum\wt@fam>\z@
\ifnum\wt@fam<16
\count@\wt@fam
\fi
\fi
\fi
\@tempcnta\wt@nucleusmathcode
\divide\@tempcnta\@cclvi
\multiply\@tempcnta\@cclvi
\advance\@tempcnta-\wt@nucleusmathcode
\@tempcnta-\@tempcnta
\edef\currentfont{\the#2\count@}%
\count@\skewchar\currentfont
\ifnum\count@=\m@ne
\wt@s\z@ % s
\else
\setbox\tw@\hbox{\currentfont\char\@tempcnta\char\count@}%
\wt@s\wd\tw@
\setbox\tw@\hbox{\currentfont\char\@tempcnta}%
\advance\wt@s-\wd\tw@
\setbox\tw@\hbox{\currentfont\char\count@}%
\advance\wt@s-\wd\tw@ % s
\fi
\else
\wt@s\z@
\fi
% If the accent character has a successor in its font whose
% width is <= u, change it to the successor and repeat this
% sentence.
% [I don't know how to do this, so I'm ignoring it.]
%
% Now set delta <- min(h(x), chi), where chi is \fontdimen5
% (the x-height in the accent font).
\edef\accentfont{\the#2\thr@@}%
\wt@delta\fontdimen5\accentfont % x-height in accent font
\ifdim\wt@delta>\ht\z@ \wt@delta\ht\z@ \fi % delta
\advance\wt@delta\p@ % Increase delta by 1pt
% If the nucleus is a single character, replace box x by a box
% containing the nucleus together with the superscript and
% subscript of the Acc atom, in style C, and make the
% sub/superscript of the Acc atom empty; also increase delta
% by the difference between the new and old values of h(x).
% [Note that we lose crampedness here since one cannot check
% for it with pdfTeX.]
\ifwt@nucleussingle
\advance\wt@delta-\ht\z@
\setbox\z@\hbox{$\m@th#1%
\the\wt@nucleus
\ifwt@sub_{\the\wt@sub}\fi
\ifwt@sup^{\the\wt@sup}\fi $}%
\wt@subfalse
\wt@supfalse
\advance\wt@delta\ht\z@
\fi
% Put the accent into a new box y, including the italic
% correction.
% [\setbox\tw@\hbox{\accentfont\char"65\/} would work except
% that I didn't find the larger accents above. Instead, use
% \widetilde and \hphantom.]
\setbox\tw@\hbox{$\m@th#1\widetilde{\hphantom{\the\wt@nucleus}}$}% box y
\wd\tw@\z@
% Let z be a vbox consisting of: boy y moved right s +
% (1/2)(u-w(y)), kern -delta, and box x.
\setbox\tw@\vbox{%
% [Since we aren't setting the accent ourself, we only
% need to move right by s since the \widetilde will
% take care of the rest.
% \moveright\dimexpr\dimen@+.5\wd\[email protected]\wd\tw@\relax\box\tw@]
\moveright\wt@s\box\tw@
\nointerlineskip
\kern-\wt@delta
\copy\z@
}% box z
% If h(z) < h(x), add a kern of h(x) - h(z) above box y and
% set h(z) <- h(x).
\ifdim\ht\tw@<\ht\z@
\dimen@\ht\z@
\advance\dimen@\ht\tw@
\setbox\tw@\vbox{%
\kern\dimen@
\unvbox\tw@
}%
\ht\tw@\ht\z@
\fi
% Finally set w(z) <- w(x),
\wd\tw@\wd\z@
% replace the nucleus of the Acc atom by box z, and continue
% with Rule 16.
%
% Rule 16:
% Change the current item to an Ord atom, and continue with
% Rule 17.
\mathord{\box\tw@}%
%
% Rule 17:
% If the nucleus of the current item is a math list [it
% isn't]...
% Then if the nucleus is not simply a symbol [it isn't], go on
% to Rule 18. ...
%
% Rule 18:
% (The remaining task for the current atom is to attach a
% possible subscript and superscript.) If both the subscript
% and superscript fields are empty, move to the next item.
% Otherwise continue with the following subrules.
% [Let's let TeX deal with subscripts and superscripts here.]
\ifwt@sub_\the\wt@sub\fi
\ifwt@sup^\the\wt@sup\fi
}
\makeatother
这需要和的mathtools
包。\cramped
etoolbox
\ifdefmacro
这是我目前的测试。请注意,\mathrm
由于某种原因,它无法正常工作。
$\widetilde{B}\wt{B}$
$\widetilde{m}\wt{m}$
$\widetilde{W}\wt{W}$
$\widetilde{w}\wt{w}$
$\widetilde{XY}\wt{XY}$
$\widetilde{\mathcal{B}}\wt{\mathcal{B}}$
$\widetilde{\mathcal{M}}\wt{\mathcal{M}}$
$\widetilde{\mathcal{W}}\wt{\mathcal{W}}$
$\widetilde{\mathcal{I}}\wt{\mathcal{I}}$
$\widetilde{\mathcal{XY}}\wt{\mathcal{XY}}$
$\widetilde{\mathrm{B}}\wt{\mathrm{B}}$
$\widetilde{\mathrm{M}}\wt{\mathrm{M}}$
$\widetilde{\mathrm{W}}\wt{\mathrm{W}}$
$\widetilde{\mathrm{I}}\wt{\mathrm{I}}$
$\widetilde{\mathrm{XY}}\wt{\mathrm{XY}}$
\newcommand\triple[2]{#1{#2}_{#1{#2}_{#1{#2}}}}
\newcommand\tw{\triple\widetilde}
\newcommand\twt{\triple\wt}
$\tw A\tw B\tw I\tw W\tw m\tw w$
$\twt A\twt B\twt I\twt W\twt m\twt w$
答案2
在 TH 的各种建议的帮助下,我想出了以下替代答案,解决了我第一次尝试的问题\phantom
。它包含一个宏的定义\wt
,该宏接受一个可选参数(降低量,默认为0.1ex
)和一个强制参数。
\documentclass{article}
\usepackage{amsmath}
\makeatletter
\newcommand*\wt[2][0.1ex]{%
\begingroup
\mathchoice{\wt@helper{#1}{#2}{\displaystyle}{\textfont}}
{\wt@helper{#1}{#2}{\textstyle}{\textfont}}
{\wt@helper{#1}{#2}{\scriptstyle}{\scriptfont}}
{\wt@helper{#1}{#2}{\scriptscriptstyle}{\scriptscriptfont}}%
\endgroup
#2%
}
\newcommand*\wt@helper[4]{%
\def\currentfont{\the#41}%
\def\currentskewchar{\char\the\skewchar\currentfont}%
\setbox\tw@\hbox{\currentfont#2\currentskewchar}%
\dimen@ii\wd\tw@
\setbox\tw@\hbox{\currentfont#2{}\currentskewchar}%
\advance\dimen@ii-\wd\tw@
\rlap{\raisebox{-#1}{$\m@th#3\kern\dimen@ii\widetilde{\phantom{#2}}$}}%
}
\makeatother
\newcommand\triple[1]{\wt{#1}_{\wt{#1}_{\wt{#1}}}}
\begin{document}
\Huge $\triple A\triple B\triple I\triple W\triple m\triple w$
\end{document}
(该amsmath
包只需要使和下标\widetilde
正常工作。我发现这个解决方案有趣的地方在于它说明了TeXbook 附录 G 第 12 条中\Huge
的作用。)\skewchar
该宏\wt
仅用于在单个“常用数学字母”上设置波浪号。更准确地说,\wt{m}
有效,\wt{WA}
有效但不能正确定位波浪号, 和 版本根本不起作用。(当然,可以构建一个宏,决定在单个“常用数学字母”的情况下使用我的解决方案,否则使用 TH 的解决方案\wt{\gamma}
。\wt{B_1}
)\wt{\mathcal{M}}