Comportamento estranho de \sbox

Comportamento estranho de \sbox

Esta questão consiste em duas partes relacionadas. Já resolvi o problema original, mas ainda não entendi de onde veio ou por que a solução funciona.

Eu uso o subcaptionpacote para poder colocar duas subtabelas uma ao lado da outra. Cada subtabela requer a largura pretendida, portanto, adicionalmente, uso a saveboxpara primeiro criar a tabela, depois medir a largura da caixa para obter a largura ideal da subtabela e, por último, mas não menos importante, imprimir o conteúdo da caixa.

\newsavebox{\tablebox}
\sbox{\tablebox}{
  \begin{tabular}{ccc}
      1st & 2nd & 3rd \\
      1   & 2   & 3   \\
      4   & 5   & 6   \\
      7   & 8   & 9   \\
  \end{tabular}
}
% create fitting subtable
\begin{subtable}{\wd\tablebox}
  \usebox{\tablebox}
  \caption{Subable}
\end{subtable}

Porém, pdflatexcomeçou a me dar o seguinte aviso

\hbox insuficiente (badness 10000) no parágrafo das linhas 24--25

onde 24 é a linha em \useboxque está.

Isso não faz sentido porque a subtabela deve ter a largura exatamente correta. Por tentativa e erro descobri que o aviso só ocorre quandotodosdas três condições a seguir são válidas:

  1. A construção fornecida é usada no apêndice (ou seja, depois \appendix).
  2. O cleverefpacote está carregado.
  3. Não há %no fim da \useboxlinha.

Não entendo por que isso tem alguma influência...

Minha segunda pergunta surgiu ao tentar localizar o erro. Troquei a segunda mesa por uma \ruledo mesmo tamanho, ou pelo menos foi o que tentei conseguir. Embora a largura ( {\wd\tablebox}) pareça boa para mim, a altura da substituição ( {\ht\tablebox}) está errada. É muito estreito. Por que?

Finalmente, um MWE que demonstra todos os efeitos descritos. Observe que não há nenhum aviso para a tabela real devido ao %mas há um para a substituição \rulecom a mesma largura:

\documentclass[english]{scrreprt}
\usepackage{babel}
\usepackage{subcaption}
\usepackage{cleveref}

\begin{document}
\appendix

\newsavebox{\tablebox}
\begin{table}
  % prepare table
  \sbox{\tablebox}{
    \begin{tabular}{ccc}
        1st & 2nd & 3rd \\
        1   & 2   & 3   \\
        4   & 5   & 6   \\
        7   & 8   & 9   \\
    \end{tabular}
  }
  % create fitting subtable
  \begin{subtable}{\wd\tablebox}
    \usebox{\tablebox}% no warning for this table
    \caption{Left Table}
  \end{subtable}
  %
  \hspace{2ex}
  %
  % create fitting subtable
  \begin{subtable}{\wd\tablebox}
    \rule{\wd\tablebox}{\ht\tablebox}
    \caption{Right Table}
  \end{subtable}

  \caption{Two Tables}
\end{table}

\end{document}

Responder1

\hbox insuficiente

O problema é o pacote cleverefque define um espaço indesejado. A linha começa com um objeto que preenche toda a linha. Normalmente as seguintes \captionchamadas \parencerram o parágrafo anterior e removem o último espaço do processo. No entanto, se houver um espaço em \captionalgum código \cleverefanterior, então apenasumo espaço é removido no final do parágrafo. O outro espaço causa uma quebra de linha e é removido no início da nova linha. Mas a nova linha já começou e está bastante vazia e o LaTeX reclama com Underfull \hbox.

Um exemplo de modelo TeX simples:

\showboxdepth=1000
\showboxbreadth=1000
\tracingonline=1
\setbox0=\vbox{%
  \noindent
  \vrule height 1pt width \hsize\relax
  \space\space
}
\showbox0
\csname @@end\endcsname\end

TeX imprime como aviso:

Underfull \hbox (badness 10000) in paragraph at lines 5--8

\hbox(0.0+0.0)x469.75499
.\glue(\rightskip) 0.0

E a caixa 0 contém:

> \box0=
\vbox(13.0+0.0)x469.75499
.\hbox(1.0+0.0)x469.75499
..\rule(1.0+*)x469.75499
..\glue(\rightskip) 0.0
.\penalty 300
.\glue(\baselineskip) 12.0
.\hbox(0.0+0.0)x469.75499
..\glue(\rightskip) 0.0

! OK.
l.9 \showbox0

Dentro da caixa vertical ( \vbox) \noindentinicia um novo parágrafo sem recuo. No final da caixa o TeX termina o parágrafo (implícito \par). Então o TeX remove um último espaço (implícito \unskip) para remover o último espaço. Neste caso, o segundo \spacee adiciona o espaço \parfillskip. Então o parágrafo antes da quebra contém:

<\vrule ...> <\space> <\hskip\parfillskip>

A regra preenche a linha completa, portanto o TeX quebra a linha após a regra antes do espaço. No início da nova linha, os espaços são removidos, portanto, ambos <\space>e <\hskip\parfillskip>são removidos. A linha contém apenas o componente inserido automaticamente \rightskipque não contém componente extensível, veja a caixa do aviso:

\hbox(0.0+0.0)x469.75499
.\glue(\rightskip) 0.0

Assim, a caixa não contém nada que preencha a linha, a linha éinsuficiente.

Soluções alternativas:

  • Comentando o final da linha (você já encontrou).
  • \parno final, os espaços subsequentes serão ignorados no modo vertical.
  • Carregando cleverefatravés de:

    \edef\RestoreEndlinechar{\endlinechar=\the\endlinechar\relax}
    \endlinechar=-1 %
    \usepackage{cleveref}
    \RestoreEndlinechar
    

    (Podem faltar espaços nas mensagens de aviso.)

O final de linha indesejado de cleveref.sty22/03/2013 v0.18.9 está localizado na definição de \refstepcounter@noargs, linha 196 e 242.

Regra incompleta

Você simplesmente esqueceu que uma caixa pode ter profundidade. O comportamento padrão de a tabularé a linha de base no meio. Mas também com a opção [b]você pode ter uma profundidade geralmente pequena, se o último elemento for uma linha normal e não um arquivo \hline.

\raiseboxpode ajudar a criar profundidade:

    \raisebox{-\dp\tablebox}{%
      \rule{\wd\tablebox}{\dimexpr\ht\tablebox+\dp\tablebox\relax}%
    }%

informação relacionada