如何降低 \widetilde 重音,即将其移近变量?

如何降低 \widetilde 重音,即将其移近变量?

我有时发现\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个主要部分。

  1. 它所做的第一件事是尝试解析将\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包。\crampedetoolbox\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}}

相关内容