测量一盒胶水总量

测量一盒胶水总量

有人给了我一个盒子,我的目标是尽可能多地了解盒子里胶水的数量。我可以假设这个盒子不是很大,但里面可能装着任意的东西(所以我不能用\unskip和朋友来解构这个盒子)。

为了明确起见,假设框\mybox是用 定义的,\newbox\mybox然后使用 构造\setbox\mybox\hbox to 50pt{a b c}。为了获取框内容的自然宽度,我可以这样做\setbox0\hbox{\unhcopy\mybox}\showthe\wd0(然后我会得到21.66669pt)。

要知道框是否包含无限拉伸,我可以在一个宽度的框内排版它\maxdimen并检查其不良性(嗯,这并非完全万无一失,但应该没问题),对于无限收缩也类似。

我感兴趣的是了解有限情况下的拉伸或收缩。我的感觉是应该可以通过使用各种方法\badness来提取它。这是正确的吗?有没有更有效的方法?\setbox0\hbox spread \somedim{\unhcopy\mybox}\somedim

答案1

简短的回答:我们可以找到盒子的自然宽度,如果它是有限的,那么可以找到确切的拉伸量(否则只能说“它是无限的”),同样,如果它是有限的,那么可以找到确切的收缩量。

为了明确起见,我们假设它\mybox是一个水平的盒子,例如

\newbox\mybox
\setbox\mybox\hbox spread 5pt{Some text perhaps.}

要找到它的自然宽度,请执行以下操作\setbox0\hbox{\unhcopy\mybox}:那么答案就是\wd0框 0 的宽度。

我们只能通过将盒子的宽度设置为不同于其自然宽度并测试 来探测粘连拉伸或收缩的量 \badness。将盒子的宽度设置为大于其自然宽度会探测拉伸分量,将其设置为小于其自然宽度会探测收缩分量。在这两种情况下,如果相应的分量(宽度较大时拉伸,宽度较小时收缩)是无限的,则 将\badness是零,这不会告诉我们有关该无限分量的值或符号的任何信息。我​​看不出有其他方法可以探测这种无限值,所以让我们专注于有限情况。

劣化程度的一般公式相当复杂:在某些情况下它涉及组合100(t/s)^3其中t是盒子的自然宽度与要求的宽度之间的差,s是拉伸量(如果盒子被挤压,则是收缩量)。幸运的是,我们可以只使用一个非常简单的情况。我们测试拉伸量的基本构造是\setbox0\hbox spread 1sp{\unhcopy\mybox\hskip 0pt plus -\stest}其中\stest是我们将改变的维度。此盒子的拉伸量是中的量\mybox减去\stest。如果为正,则盒子可以拉伸,并且\badness不会太大(结果是 100 或更小)。否则,盒子未满,因为它甚至无法拉伸 1sp,并且为\badness10000(在测试收缩时,我们得到的盒子过满,为1000000)。因此,我们有一个简单的方法来测试对于任何维度\badness的拉伸量是否\mybox>\stest或 。因此,任务简化为二分法。<=\stest\stest

\hbadness=1000000
\hfuzz=\maxdimen
\newdimen\stest
\newdimen\smin
\newdimen\smax
\def\find#1#2#3{%
  \smin = -\maxdimen
  \smax = \maxdimen
  \loop
    \stest = \smin
    \advance \stest by \smax
    \divide \stest by 2 % now \stest=(\smin+\smax)/2 truncated to 0
    \ifdim \stest = \smax
      \advance \stest by -1sp % ensure that \smin<=\stest<\smax.
    \fi
    \setbox 0 = \hbox spread #2 1sp {%
      \unhcopy\mybox
      \hskip 0pt #3-\stest
    }%
    \ifnum \badness > 100 % (shrink/stretch in \mybox) <= \stest
      \smax = \stest
    \else
      \smin = \stest
      \advance \smin by 1sp
      % since ">\stest" implies ">=\stest+1sp"
    \fi
    % In both cases, the interval [\smin,\smax] becomes smaller.
  \ifdim\smin<\smax
  \repeat
  \ifdim\smin>\smax\BOOM\fi% cannot happen, I think
  \message{^^JThe #1 is
    \ifdim\smin=\maxdimen infinite\else\the\smin\fi.}% (\smin=\smax)
}
\setbox0\hbox{\unhcopy\mybox}
\message{^^JThe natural width is \the\wd0 .}
\find{stretch}{}{plus}
\find{shrink}{-}{minus}

答案2

如果\mybox是 vbox,那么我们几乎可以完全解决问题,方法是保存当前页面、将框内容转储到主垂直列表上、\pagestretch在输出例程中累积和朋友,然后恢复当前页面。

此方法不能用于测量无限收缩粘连,因为 TeX 不允许在主垂直列表中使用此类粘连。正如 Bruno 指出的那样,您至少可以通过在高度为 的垂直框中将其拆箱并检查 来检查该框是否包含无限收缩-\maxdimen粘连\badness

\newbox\savedpage
\newdimen\savedprevdepth
\newdimen\stretch
\newdimen\filstretch
\newdimen\fillstretch
\newdimen\filllstretch
\newdimen\shrink
\def\savepage{%
    \savedprevdepth=\prevdepth
    {\output={\global\setbox\savedpage=\box255}%
    \holdinginserts=1 \eject}}
\def\restorepage{\unvbox\savedpage \prevdepth=\savedprevdepth}
\def\findglue{%
    \savepage
    \stretch=0pt
    \filstretch=0pt
    \fillstretch=0pt
    \filllstretch=0pt
    \shrink=0pt
    \begingroup
        \output={%
            \global\advance\stretch\pagestretch
            \global\advance\filstretch\pagefilstretch
            \global\advance\fillstretch\pagefillstretch
            \global\advance\filllstretch\pagefilllstretch
            \global\advance\shrink\pageshrink
            \setbox0=\box255
            \null % Keep discardables after page break.
        }%
        \vsize=\maxdimen
        \topskip=0pt
        \null % Keep discardables at top of mybox.
        \unvcopy\mybox
        \eject
        \output={\setbox0=\box255}%
        \eject % Remove the \null and \penalty10000 remaining on the page.
    \endgroup
    \restorepage}

% Only needed for the print-out
{\catcode`\p=12 \catcode`\t=12 \gdef\\#1pt{#1}}
\def\decimal{\expandafter\\\the}

\setbox0=\vbox{\boxmaxdepth=0pt \unvcopy\mybox}
\findglue
Height-plus-depth of box:
\the\ht0\ 
plus \the\stretch\ 
plus \decimal\filstretch fil
plus \decimal\fillstretch fill
plus \decimal\filllstretch filll
minus \the\shrink

\savepage和宏\restorepage假设您没有手动触摸\pagegoal\pagetotal等,并且\topskip自保存的页面启动以来这些内容没有发生变化。如果不是这种情况,除了页面内容之外,您还应该保存和恢复这些数量。

相关内容