下面的示例给出了重叠的图形(图形与自身重叠以及图形与文本重叠),如下图所示。
h
如果我更改周围的文本、图像大小或删除第二个图形的 -placement 修饰符,我可以解决这个问题。使用\raggedbottom
重叠也会消失。该示例给出了 vbox 未满警告,但在出现这些警告的其他页面上,LaTeX 只会拉伸垂直跳跃,因此它看起来不再那么好,但至少它仍然可读。
那么为什么会发生这种情况?有没有办法解决这个问题,而不用重写一些文本或不把图放在“这里”?
\documentclass[parskip=half]{scrbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\begin{document}
\begin{figure}[th]
\fbox{\parbox[c][6cm]{7cm}{img 1}}
\caption{caption 1}
\end{figure}
x\\x\\x\\x\\x\\x\\x\\x\\x\\x\\x
\begin{figure}[th]
\raggedleft
\fbox{\parbox[c][4cm]{5cm}{img 2}}
\caption{caption 2}
\end{figure}
\section{A section}
y\\y\\y\\y\\y
\end{document}
答案1
多么有趣的问题啊!
事实证明,这(可能是)自古以来 LaTeX 就存在的一个错误,但由于它涉及到非常微妙的领域(TeX 有其局限性),即使我们想尝试它,我也不确定是否有安全的解决方案 --- 我稍后会提供一个解决方案,但可能存在我还没有想到的其他问题。
那么问题是什么?首先我们需要一些非常特殊的情况
scrbook
有选项parskip=half
是必需的- 该页面需要一些非常特殊的结构
- 浮子
h
需要位于最底部
可以进一步缩短 MWE,这有助于我查明问题所在:
\documentclass[parskip=half]{scrbook}
\tracingonline1\tracingpages1
\begin{document}
\begin{figure}[th]
\fbox{\parbox[c][6cm]{7cm}{img 1}}
\caption{caption 1}
\end{figure}
x\\x\\x\\x\\x\\x\\x\\x\\x\\x\\x
\begin{figure}[h]
\raggedleft
\fbox{\parbox[c][4cm]{5cm}{img 2}}
\caption{caption 2}
\end{figure}
\addvspace{3cm}
\addpenalty{-300}
Z
\end{document}
我添加的最重要的一行是
\tracingonline1\tracingpages1
这让我们跟踪了页面中断的情况。如果我们运行它,我们会得到
%% goal height=595.80026, max depth=5.5 % t=0.0 g=595.80026 b=10000 p=0 c=100000# % t=11.0 g=595.80026 b=10000 p=-10003 c=-10003# %% goal height=595.80026, max depth=5.5 % t=0.0 g=595.80026 b=10000 p=0 c=100000# % t=202.1165 g=595.80026 b=10000 p=0 c=100000# % t=227.7165 plus 2.0 minus 2.0 g=595.80026 b=10000 p=150 c=100000# % t=241.31651 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=254.91652 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=268.51653 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=282.11653 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=295.71654 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=309.31654 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=322.91655 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=336.51656 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=350.11656 plus 2.0 minus 2.0 g=595.80026 b=10000 p=150 c=100000# % t=363.71657 plus 2.0 minus 2.0 g=595.80026 b=10000 p=-10004 c=-10004# %% goal height=16383.99998, max depth=5.5 % t=11.0 g=16383.99998 b=10000 p=-10003 c=-10003# %% goal height=595.80026, max depth=5.5 % t=0.0 g=595.80026 b=10000 p=0 c=100000# % t=202.1165 g=595.80026 b=10000 p=0 c=100000# % t=227.7165 plus 2.0 minus 2.0 g=595.80026 b=10000 p=150 c=100000# % t=241.31651 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=254.91652 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=268.51653 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=282.11653 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=295.71654 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=309.31654 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=322.91655 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=336.51656 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=350.11656 plus 2.0 minus 2.0 g=595.80026 b=10000 p=150 c=100000# % t=363.71657 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=520.92757 plus 4.0 minus 4.0 g=595.80026 b=10000 p=0 c=100000# % t=526.12756 plus -0.8 minus 6.0 g=595.80026 b=10000 p=-300 c=100000# % t=631.88583 plus 6.0 minus 6.0 g=595.80026 b=* p=0 c=* Underfull \vbox (badness 10000) has occurred while \output is active []
这显示了如何添加第一个浮点数,c=-10003
然后添加所有带有浮点数的行,x
直到我们有
% t=363.71657 plus 2.0 minus 2.0 g=595.80026 b=10000 p=-10004 c=-10004#
对应于此处的第二个浮动。此时页面已重建,因此我们会看到所有行再次出现,然后以此结尾:
% t=363.71657 plus 2.0 minus 2.0 g=595.80026 b=10000 p=0 c=100000# % t=520.92757 plus 4.0 minus 4.0 g=595.80026 b=10000 p=0 c=100000# % t=526.12756 plus -0.8 minus 6.0 g=595.80026 b=10000 p=-300 c=100000# % t=631.88583 plus 6.0 minus 6.0 g=595.80026 b=* p=0 c=*
第一行是最后x
一行,然后出现了一个很大的跳跃,t=
因为我们在这里添加了第二个浮点数,然后t=526.12756
我们看到一个p=-300
,IE,我们的明确惩罚。我们没有看到空间,3cm
因为\addpenalty
将自己移动到了前面的跳过之前。
最后一行意味着c=*
我们有太多的内容(现在增加了 3 厘米)。因此,分页符是在前面一行的明确惩罚处进行的,IE, 在
% t=526.12756 plus -0.8 minus 6.0 g=595.80026 b=10000 p=-300 c=100000#
现在如果你看一下这个跟踪输出(并且你已经准备好了 TeXbook,或者 LaTeX Companion,或者你已经记住了这些东西 :-)),那么你会注意到为什么页面会这样显示... 你注意到了吗? 不?
好的,我们开始吧:
- 页面高度为,
t=526.12756
但页面目标是,g=595.80026
所以我们太短,页面材料需要拉伸; - 然而,拉伸部分
plus -0.8
在这条线上实际上是负的(而且只有这条线),所以为了从到拉伸,526pt
我们595pt
必须将其乘以-86
(大致); - 因此 TeX 继续将页面上所有粘连的“加号”部分乘以
-86
; - 现在,在第一个浮点数之后有一个粘合,即
12pt plus 2pt minus 2pt
,所以如果将它的加号部分相乘,-86
我们就会得到总共的12pt plus -172pt
跳过,这将-es-150pt
的线向上驱动;x
- 同样的,在第二个浮标的前面也有这样一个空间,这样人们就可以驱动浮标向上移动
-150pt
,这就是你发送的内容。
因此剩下的问题是,为什么我们最终会在这条线上得到这个负的“加号部分”?
这个问题的答案隐藏在一个名为的宏中,\@addcurcol
该宏的任务是将浮点数附加到适当的位置。如果出现“此处浮点数”,它将执行以下代码:
\vskip \intextsep
\box\@currbox
\penalty\interlinepenalty
\vskip\intextsep
\ifnum\outputpenalty <-\@Mii \vskip -\parskip\fi
在它的最后,它会在某些情况下发出问题(当在垂直模式下遇到浮动时)\vskip - \parskip
,并且\parskip
由于6.8pt plus 6.8pt
选择,scrbook
我们最终得到
\vskip -6.8pt plus -6.8pt
并将页面上其余的加号部分完全加上6pt
(你可以在上面的描图中看到)我们得到了整体plus -0.8
……然后我们就得到了……叹息。
那么这里出了什么问题?这个负数\parskip
被添加到此处的浮动之后,以说明另一个即将被添加的事实\parskip
,如果我们不将其取消,间距将看起来非常不均匀 --- 尤其是如果您\parskip
一开始就有一个较大的浮动,如示例中所示。
但是,在我们的示例中,我们最终在它之后得到了一个分页符,因此后面没有任何需要取消的 parskip,所以我们有这个额外的负数,它确实搞乱了页面计算。
换句话说,分页符不应该出现在那里,而应该出现在负数之前\parskip
,或者实际上应该出现在\intextsep
浮动元素之后。但这很难安排。像\addpenalty
或 这样的元素\addvspace
永远看不到这个空间(因为它是在输出例程中添加的,当输出例程结束时,您将自动\penalty 10000
在最后添加一个,这会隐藏之前的任何内容。
所以我尝试了一种不同的方法:
- 计算输出例程中要添加的空间(
\intextsep
或);\intextsep - \parskip
\vskip
然后仅在输出例程结束后通过使用将其推出来添加\aftergroup
。
因此将其应用到原始 MWE 我们得到:
\documentclass[parskip=half]{scrbook}
\tracingonline1\tracingpages1
\usepackage{etoolbox}
\makeatletter
\patchcmd\@addtocurcol
{\vskip\intextsep \ifnum\outputpenalty <-\@Mii \vskip -\parskip\fi}
{\calc@after@float@skip
\aftergroup\add@after@float@skip}
{\typeout{Patch Successfully applied}}{\typeout{Patch failed!}\ERROR}
\def\calc@after@float@skip{
\@tempskipa\intextsep
\ifnum\outputpenalty <-\@Mii \advance\@tempskipa-\parskip \fi
\xdef\add@after@float@skip{\vskip\the\@tempskipa\relax}%
}
\makeatother
\begin{document}
\begin{figure}[th]
\fbox{\parbox[c][6cm]{7cm}{img 1}}
\caption{caption 1}
\end{figure}
x\\x\\x\\x\\x\\x\\x\\x\\x\\x\\x
\begin{figure}[h]
\raggedleft
\fbox{\parbox[c][4cm]{5cm}{img 2}}
\caption{caption 2}
\end{figure}
\section{A section}
y\\y\\y\\y\\y
\end{document}
结果是
但不能保证这不会改变其他文档,因为这现在会改变此处靠近页面末尾的浮动后的间距。
答案2
因此,这是一个不幸的时机,在这里将两个浮动元素添加到空白页,并决定是否在节标题处中断。
到目前为止还没有完全追踪它(我可能会放弃并问弗兰克:-)但你可以通过\clearpage
在该部分之前添加无论如何都会中断页面的点来简化乳胶的决策。
\documentclass[parskip=half]{scrbook}
\usepackage{fltrace}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\begin{document}
\tracefloats
\begin{figure}[th]
\fbox{\parbox[c][6cm]{7cm}{img 1}}
\caption{caption 1}
\end{figure}
x\\x\\x\\x\\x\\x\\x\\x\\x\\x\\x
\begin{figure}[th]
\raggedleft
\fbox{\parbox[c][4cm]{5cm}{img 2}}
\caption{caption 2}
\end{figure}
\clearpage
\section{A section}
y\\y\\y\\y\\y
\end{document}