7

How can I determine the height and depth of a "multi-line" \ooalign?

\ooalign{\relax\cr%
         \noalign{\vskip-2ex}X\cr%
         \noalign{\vskip+2ex}\cr%
         \noalign{\vskip+1ex}X\cr%
         \noalign{\vskip-1ex}%
        }%

With the answers to Depth and height confusion I seem to get just the dimensions of the lower part of the \ooalign.

  • 1
    If I recall, this the height/depth is dependent on the first/last elements. Your first and last have no height/depth. – Werner Jun 24 '15 at 18:05
  • @Werner: Yes, when trying to measure this, it is indeed 0pt large, but when printed it is not, of course. Thus I would like to know the height of the "inked area". – Stephen Jun 24 '15 at 18:21
4

Analysis

\ooalign uses \vtop. If the first element is a box, then its height becomes the height of \ooalign, otherwise the height is 0 pt. Without \noalign at the start of \ooalign, the first element is the first row, then \ooalign has the height of the first row. In this case the row is empty (\relax), thus the height is 0 pt.

The depth is more complicate. TeX first sets the contents of \vtop in a \vbox. Then TeX gets the height as described above and moved the reference point accordingly. Thus the depth is the total height of the \vbox minus the height from above.

Because of the paragraph parameter settings, the rows in \ooalign do not move their reference points, thus the rows overwrite the previous rows. Therefore only the last depth and the sum of the contributions of \noalign are having an effect for the overall depth. In this case, the sum of the \noalign{\vskip...} contributions is 0 pt as well as the depth of the last row. Thus the depth of the \ooalign is 0 pt.

Macro \charsovereachother (without \noalign)

The following macro \charsovereachother can be used instead of \ooalign, when the user wants to have the height and depth as maximum of all rows in \ooalign. (Makes only sense without manual movements via \noalign{\vskip...}).

The test file is written for plain TeX, but the macro can also be used in LaTeX:

\edef\RestoreAtCatcode{\catcode`\noexpand\@=\the\catcode`\@\relax}
\catcode`\@=11
\newdimen\COEO@height
\newdimen\COEO@depth
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname protected\endcsname\relax
\else
  \expandafter\protected
\fi 
\def\charsovereachother#1{%
  \leavevmode
  \begingroup
    \setbox0\vtop{%
      \baselineskip0pt\relax
      \lineskip0pt\relax
      \lineskiplimit=-16383.99999pt\relax
      \gdef\COEO@height{0pt}%
      \gdef\COEO@depth{0pt}%
      \everycr{}\tabskip0pt\halign{%
        % the cell contents is measured and
        % the maximum values for height and depth are remembered
        \setbox0\hbox{##}%
        \ifdim\COEO@height<\ht0 %
          \xdef\COEO@height{\the\ht0}%
        \fi
        \ifdim\COEO@depth<\dp0 %
          \xdef\COEO@depth{\the\dp0}%
        \fi
        \unhcopy0 %
        \crcr
        #1%
        \crcr
      }%
    }%  
    \vtop{%
      % update the height if necessary
      \ifdim\COEO@height>\ht0 %
        \hrule width0pt height\COEO@height depth0pt %
        \kern-\ht0 %
      \fi
      \unvcopy0 %
      % update the depth if necessary
      \ifdim\COEO@depth>\dp0 %
        \kern-\dp0 %
        \kern\COEO@depth
      \fi   
    }%
  \endgroup
}%
\RestoreAtCatcode

% Test

\hrule

\ooalign{a. row$_{\hbox{(1st line)}}$\hfill\cr
  \kern10em last row$^{\hbox{(2nd line)}}$}

\hrule

\bigskip

\hrule  

\charsovereachother{a. row$_{\hbox{(1st line)}}$\hfill\cr
  \kern10em last row$^{\hbox{(2nd line)}}$}

\hrule

\bye

Result

| improve this answer | |
  • +1 and thanks for the explanation of what is happening (instead of just giving a solution)! – Stephen Jun 25 '15 at 20:11
1

Heiko's \charsovereachother can be directly emulated with a properly configured \Longstack from the stackengine package.

\documentclass{article}
\usepackage{stackengine}
\setstackEOL{\cr}\setstackgap{L}{0pt}\def\stackalignment{l}
\begin{document}
\hrule  

\Longstack{a. row$_{\hbox{(1st line)}}$\hfill\cr
  \kern10em last row$^{\hbox{(2nd line)}}$}

\hrule
\end{document}

enter image description here

Note the \hfill can be eliminated from the argument, but I left it there to match the argument used by Heiko.

Note also that \vskips are not permitted in the stacking arguments, but can be simulated in other ways, depending on the problem. For example, the MWE of the OP is easily performed with a stack. As one can see, the height and depth of the stack are properly captured by the \hrule boundary lines.

\documentclass{article}
\usepackage{stackengine}
\begin{document}
\hrule

\ooalign{\relax\cr%
         \noalign{\vskip-2ex}Q\cr%
         \noalign{\vskip+2ex}\cr%
         \noalign{\vskip+1ex}X\cr%
         \noalign{\vskip-1ex}%
        }%
\def\stacktype{L}
\stackunder[1ex]{\stackon[2ex]{}{Q}}{X}

\hrule
\end{document}

enter image description here

| improve this answer | |
  • +1 & thanks for this short solution just requiring 1 package. – Stephen Jun 25 '15 at 20:12
1

After reading the answer of Heiko Oberdiek, I understood (at least something of) the meaning of the original code.

After reading the answer of Steven B. Segletes, I could simplify the original code to

\Longstack{%
           \raisebox{+2ex}{X}\cr%
           \raisebox{-1ex}{X}\cr%
           }

(with package and configuration as in Steven B. Segletes' answer).

Just to get height and depth of this, also measuring the replacement

\raisebox{+2ex}{X}
\raisebox{-1ex}{X}

works, i.e.

\newlength\myHeight
\newlength\myDepth

\settoheight{\myHeight}{%
  \raisebox{+2ex}{\vphantom{X}}%
  \raisebox{-1ex}\vphantom{{X}}% this line only needed when this "lower X" 
                               % would reach higher than the "upper X"
}%

\settodepth{\myDepth}{%
  \raisebox{+2ex}{\vphantom{X}}% this line only needed when this "higher X"
                               % would reach deeper than the "lower X"
  \raisebox{-1ex}{\vphantom{X}}%
}%

where I added \vphantoms for the case when "XX" is wider than \textwidth (but neither "higher X" nor "lower X" is wider).

Then

\hbox{\vrule\@height\myHeight%
                    \@depth\myDepth%
                    \@width\z@}

has height and depth of the \ooalign{...} (and width zero).

MWE:

\documentclass{article}

\newlength\myHeight
\newlength\myDepth

\begin{document}
\makeatletter

\hrule
\ooalign{\relax\cr%
         \noalign{\vskip-2ex}{X}\cr%
         \noalign{\vskip+2ex}\cr%
         \noalign{\vskip+1ex}{X}\cr%
         \noalign{\vskip-1ex}%
        }% 
%
\settoheight{\myHeight}{%
  \raisebox{+2ex}{\vphantom{X}}%
  \raisebox{-1ex}\vphantom{{X}}% 
 }%
\settodepth{\myDepth}{%
  \raisebox{+2ex}{\vphantom{X}}%
  \raisebox{-1ex}{\vphantom{X}}%
 }%
\hbox{\vrule\@height\myHeight%
            \@depth\myDepth%
            \@width\z@}%
\hrule 

\makeatother 
\end{document}

resulting in this output:

Result

(which I would have never come to without the other two answers - thanks!).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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