Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I sometimes find that the \widetilde accents sits too high above the math letter it is applied to. An example:

To me it looks as if the first tilde is sitting just in between the two lines; it is not visually attached to the "B". As the second "B tilde" shows, I did manage to produce a version where the \widetilde is lowered, but this is an ugly hack using \textcolor:

\rlap{\raisebox{-0.1ex}{$\widetilde{B}$}}
\rlap{\smash{\textcolor{white}{\rule[-1ex]{2em}{2.7ex}}}}
B

What I'm doing here: I lower the whole \widetilde{B}, then I erase the "B" by some (manually adjusted) white box, and finally I typeset the "B" that is seen in the output. Of course I have this wrapped in some macro, but this macro does not work for small letters such as "m", which is due to the white box.

The more straightforward attempt

\rlap{\raisebox{-0.1ex}{$\widetilde{\phantom{B}}$}}B

does not work as the output shows: the tilde in is too far to the left. The reason for this is that TeX handles accents over single characters differently, using the \skewchar of the font, and \phantom{B} is not a single character. Moreover, in the version \tilde B I find the tilde too small: .

One of the problems of my solution is that it doesn't render properly when I view the dvi file in Yap. Does anyone know a better solution to lower the \widetilde?

EDIT:

TH's first solution works rather well. It has the only drawback that it does not lower the \widetilde over small letters such as "m". However, this is not a big deal since in this case the tilde does not look as if it is sitting in between two lines. I came up with an answer that does lower the \widetilde over "m", but that has other major problems. TH's (rather involved) second solution fixes most of these problems. Great work!

share|improve this question
    
You may wish to read eutypon.gr/eutypon/pdf/e2000-05/e05-a04.pdf (however I couldn't find the package on CTAN). It has very useful information on accents and the parameters to manipulate them. –  Yiannis Lazarides Oct 9 '10 at 14:35
    
@Yiannis: I think this won't help since it is about accents in text mode, which are quite different from accents in math mode. –  Hendrik Vogt Oct 9 '10 at 15:02
    
fyi, I tracked the accentbx files down and put them up on github here: github.com/zellyn/accentbx –  zellyn Dec 21 '11 at 20:31
    
@zellyn Thanks for tracking it down and posting it on github. –  Yiannis Lazarides Jan 8 '12 at 16:53

2 Answers 2

up vote 9 down vote accepted

Implementation 1
This code changes the x-height of the accent font for its argument. It should be fairly robust. Rather than scaling the height by 1.3, one could simply add a fixed value to it. Because of the way TeX computes accent heights, there is some minimum height of an accent and so this tends to have no discernible effect on lowercase letters.

\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

Implementation 2
This attempts to duplicate Rule 12 and the relevant portions of Rules 16–18 in Appendix G of The TeXbook for typesetting math accents.

Some notes on the implementation: I don't know how to compute successors, so instead I replace box y which should just be the accent and the italic correction with $\widetilde{\hphantom{...}}$. As a result, the tilde should already be shifted by half(w+width(y)). From tex.web, the shift amount of box y is given by
shift_amount(y):=s+half(w-width(y));
thus it suffices to compute the kerning s and shift right by that amount.

The code below contains 3 main parts.

  1. The first thing it does is tries to parse the argument to \wt which will appear as the nucleus of the Acc atom. This is extremely brittle. If the argument expands to any primitives other than \relax, \bgroup, \egroup, \begingroup, \endgroup, \fam, (control space), \char (not tested), \mathchar (not tested), \mathcode (not tested), a letter, or a symbol, it will treat the nucleus as not a single character even if it really is. If there is an unknown control sequence, for example \let\unknown\foo, it will fail with a mysterious error because it cannot expand \unknown. Some effort is put into checking for changes of fonts.

    If the \wt@checknucleus macro decides that the nucleus of the Acc atom we're about to fake is just a single character, it stores the \mathcode and notes the fact by setting \ifwt@nucleussingle to \iftrue. (I suppose the third part of the code could just check the saved math code instead.)

    • After \wt@checknucleus is complete, it scans ahead looking for _ and ^. If these are hidden in macros, it won't find them! Any subscripts and superscripts are saved for later processing in either Rule 12 or Rule 18.

    • Finally, \wt@choice uses \mathchoice to typeset the formula in each of the 4 styles which is done by \wt@applyrules and then pick the appropriate one. \wt@applyrules contains the relevant rules from The TeXbook as comments followed by some code that attempts to apply the rules.

The code is not perfect. See the output from my test at the bottom of this answer. Also, it loses crampedness because pdfTeX provides no way to test for it. It does perform the appropriate cramping where Rule 12 calls for it.

\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\z@-.5\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

This requires the mathtools package for \cramped and etoolbox for \ifdefmacro.

This is my current test. Note that \mathrm doesn't work properly for some reason.

$\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$
share|improve this answer
    
@TH: Both your solutions look very interesting, so +1 for now. Before I accept the answer, I'll have to understand (even) better what you're doing. What I understood so far: Both your solutions have a similar (very good) effect. However, they do not lower the tilde over small letters such as "m", and I think this is due to the minimum of h(x) and \chi in rule 12. Nevertheless, it's already very helpful for my needs. Thanks for your help! –  Hendrik Vogt Oct 3 '10 at 20:24
    
@Hendrik Vogt: Yes, I think you're right regarding h(x) and χ. –  TH. Oct 3 '10 at 20:28
    
@TH: Looking closer I see that your second solution is no good: Just try it with "W" instead of "B"; there the tilde is much too far to the right. Using the italic correction here is not the right idea (and it is not in the spririt of rule 12). Still the method with the \currentfont is very interesting. –  Hendrik Vogt Oct 3 '10 at 20:46
    
@Hendrik Vogt: I'm not sure I agree with your assessment of not being in the spirit of rule 12. It does say, "Put the accent into a new box y, including the italic correction." Unless Knuth means the italic correction of the accent itself, it's doing something with the italic correction of the nucleus. –  TH. Oct 3 '10 at 20:54
    
@Hendrik Vogt: I just reread the paragraphs that proceed the list of rules and I think that the italic correction might actually be for the accent. –  TH. Oct 3 '10 at 21:11

With the help of TH's various suggestions I came up with the following alternative answer that fixes my first attempt with \phantom. It contains the definition of a macro \wt that takes one optional argument (the lowering amount, defaults to 0.1ex) and one mandatory argument.

\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}

(The amsmath package is only needed to make \widetilde work properly with \Huge and subscripts. What I find interesting about this solution is that it illustrates the role of the \skewchar in rule 12 of Appendix G in the TeXbook.)

The macro \wt should only be used for setting a tilde over a single "usual math letter". To be more precise, \wt{m} works, \wt{WA} works but doesn't position the tilde correctly, and the versions \wt{\gamma}, \wt{B_1} and \wt{\mathcal{M}} don't work at all. (Of course it would be possible to construct a macro that decides to use my solution in the case of a single "usual math letter", and TH's solution otherwise.)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.