% \iffalse meta-comment % % Copyright (C) 2011--2020 by Leo Liu % --------------------------------------------------------------------------- % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Leo Liu. % % This work consists of the files diagbox.dtx and diagbox.ins % and the derived filebase diagbox.sty. % % \fi % % \iffalse %<*driver> \ProvidesFile{diagbox.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{diagbox} %<*package> [2020/02/09 v2.3 Making table heads with diagonal lines] % % %<*driver> \documentclass[letterpaper]{ltxdoc} \AtBeginDocument{ \DeleteShortVerb{\|} \MakeShortVerb{\"}} \usepackage{diagbox} \usepackage{xcolor} \usepackage[left=1.7in,top=1in,bottom=1in]{geometry} \usepackage{fancyvrb-ex} \usepackage{amsmath} \usepackage[UTF8]{ctex} \setmainfont{Latin Modern Roman} \setsansfont{Latin Modern Sans} \setmonofont{Latin Modern Mono} \makeatletter \renewcommand\glossary@prologue{% \section*{版本历史} \markboth{版本历史}{版本历史}} \renewcommand\index@prologue{% \section*{Index / 代码索引} \markboth{Index / 代码索引}{Index / 代码索引} 斜体的数字表示对应项说明所在的页码。下划线的数字表示定义所在的代码行号;而直 立体的数字表示对应项使用时所在的行号。} \renewcommand*\title[2][]{\gdef\@title{#2}} \renewcommand*\author[2][]{\gdef\@author{#2}} \providecommand\eTeX{$\m@th\varepsilon$-\TeX} \makeatother \usepackage[numbered]{hypdoc} \hypersetup{pdfstartview=FitH} \fvset{gobble=1} %% 删除例子代码开头的 % \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{diagbox.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{901} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v1.0}{2011/11/21}{初始版本。} % % \DoNotIndex{\newcommand, \newenvironment, \@nameuse, \@pkgextension, % \@reserveda, \@tfor, \begin, \begingroup, \box, \csname, \def, \define@key, % \dimexpr, \do, \dp, \edef, \else, \end, \endcsname, \endgroup, \endinput, % \expandafter, \fi, \hbox, \ht, \ifcsname, \ifdim, \ifx, \Line, \makebox, % \newbox, \newdimen, \p@, \PackageError, \pkg, \put, \relax, \RequirePackage, % \setbox, \setkeys, \setlength, \strip@pt, \unexpanded, \unitlength, % \vcenter, \wd, \xdef, \z@, \@ifnextchar, \bgroup, \FPadd, \FPmul, \FPneg, % \FPsub, \FPupn, \let, \unless, \hspace, \@tempskipa, \newif, \detokenize, % \@@, \\, \c, \l, \cs, \fp, \dim, \msg, \scan} % % \providecommand*{\pkg}{\textsf} % \GetFileInfo{diagbox.dtx} % \title[diagbox Package (\fileversion): % Making Table Heads with Diagonal Lines]% % {\hypertarget{English}{\pkg{diagbox} Package (\fileversion)} % \makebox[0pt][l]{\hspace{3cm}\large % \hyperlink{Chinese}{$\Rightarrow$ \textsf{中文版}}}\\ % Making Table Heads with Diagonal Lines} % \author[Leo Liu ]% % {Leo Liu \\ \path{leoliu.pku@gmail.com}} % \date{\filedate} % % \maketitle % % \section{Introduction} % % \pkg{diagbox} is a replacement of old \pkg{slashbox} package\footnote{By % Koichi Yasuoka and Toru Sato. Available on % \url{CTAN://macros/latex/contrib/slashbox/slashbox.sty}}. I write this % package simply because that \pkg{slashbox} is not available in \TeX\ Live % for licening problems. \pkg{slashbox} has no explicit license information % available, but \pkg{diagbox} is under LPPL. % % \pkg{diagbox} is a modern alternative of \pkg{slashbox}. I changed the % user interface to use a key-value syntax, get rid of some restrictions of % \pkg{slashbox}, use \pkg{pict2e} to draw diagonal lines. Especially, this % package also provides ability to make a box with two diagonal lines in it. % All these can be obtained by a "\diagbox" command. % % As a replacement of \pkg{slashbox}, \pkg{diagbox} package also provides % compatible macros of \pkg{slashbox}, but the result is a little different. % % To use \pkg{diagbox}, \eTeX{} is needed. And \pkg{diagbox} requires % \pkg{pict2e}, \pkg{keyval}, \pkg{calc}, and \pkg{fp} packages. % % % \section{Usage} % % \subsection{Basic usage} % % To load the package, just put this in the preamble: % \begin{Verbatim} % \usepackage{diagbox} % \end{Verbatim} % % \DescribeMacro{\diagbox} % "\diagbox" is the main command. It can take two arguments, to produce a box % with a diagonal line from north west to south east. % % For example:\\ % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|l|ccc|} % \hline % \diagbox{Time}{Day} & Mon & Tue & Wed \\ % \hline % Morning & used & used & \\ % Afternoon & & used & used \\ % \hline % \end{tabular} % \end{SideBySideExample} % \medskip % % "\diagbox" can also take three arguments, to draw a table head with two % diagonal lines. For example, % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|l|ccc|} % \hline % \diagbox{Time}{Room}{Day} & Mon & Tue & Wed \\ % \hline % Morning & used & used & \\ % Afternoon & & used & used \\ % \hline % \end{tabular} % \end{Example} % % \subsection{More options} % % "\diagbox" can take a key-value list as an optional argument to specify the % width and height of the box, the direction of the diagonal line, and the % trimming margins: % \begin{description} % \item[width] Specify the width of the box explicitly. If it is omitted, % \pkg{diagbox} will calculate the width automatically. % % \item[height] Specify the height of the box explicitly. If it is omitted, % \pkg{diagbox} will calculate the height automatically. In the argument, one % can use "\line" as a line height. % % \item[dir] Specify the direction of the diagonal line. The value can be % "NW", "NE", "SW" and "SE". Default value is "NW". The meaning of the values % see below. % \begin{itemize} % \item "\diagbox[dir="\meta{direction}"]{A}{B}" in a table looks:\\ % \begin{tabular}{ll@{\qquad}ll} % "NW" or "SE":& % \begin{tabular}{|c|} \hline \diagbox[dir=SE]{A}{B} \\\hline \end{tabular} & % "SW" or "NE":& % \begin{tabular}{|c|} \hline \diagbox[dir=NE]{A}{B} \\\hline \end{tabular} % \end{tabular} % \item "\diagbox[dir="\meta{direction}"]{A}{M}{B}" in a table looks:\\ % \begin{tabular}{*4{ll@{\qquad}}} % "NW"& % \begin{tabular}{|c|} \hline \diagbox[dir=NW]{A}{M}{B} \\\hline \end{tabular}& % "NE"& % \begin{tabular}{|c|} \hline \diagbox[dir=NE]{A}{M}{B} \\\hline \end{tabular}& % "SW"& % \begin{tabular}{|c|} \hline \diagbox[dir=SW]{A}{M}{B} \\\hline \end{tabular}& % "SE"& % \begin{tabular}{|c|} \hline \diagbox[dir=SE]{A}{M}{B} \\\hline \end{tabular} % \end{tabular} % \end{itemize} % % \item[innerwidth] Specify the width of the inner content box. "innerwidth" % option is useful when specifying column width. For example: % \begin{Example} % \begin{tabular}{|p{2cm}|} \hline % \diagbox[innerwidth=2cm]{A}{B} \\ \hline % \end{tabular} % \end{Example} % % \item[innerleftsep, innerrightsep] Specify the distances between the border % of the inner content box and the border of the diagonal box. We have: % \[ % "innerleftsep" + "innerwidth" + "innerrightsep" = "width". % \] % For example: % \begin{Example} % \begin{tabular}{|c|} \hline % \diagbox[innerleftsep=.5cm,innerrightsep=0pt]{A}{B} \\ \hline % \end{tabular} % \end{Example} % % \item[outerleftsep, outerrightsep] Specify the distances between the border % of the diagonal box and the border of the tabular cell. Usually they are % negative values, which satisfy % \begin{align*} % "outerleftsep" + "LEFTtabcolsep" &= 0\,\mathrm{pt}, \\ % "outerrightsep" + "RIGHTtabcolsep" &= 0\,\mathrm{pt}. % \end{align*} % where "LEFTtabcolsep" and "RIGHTtabcolsep" are the distances between % verticle lines and the tabular cell content (the diagonal box). For example: % \begin{Example} % \begin{tabular}{|r@{\hspace{20pt}}|l|} \hline % \diagbox[outerrightsep=-20pt]{A}{B} & C \\ \hline % AABB & CC \\ \hline % \end{tabular} % \end{Example} % % \item[leftsep, rightsep] Specify the left and right distances, which are % equivalent to: % \begin{align*} % "innerleftsep" &:= "leftsep", & "innerrightsep" &:= "rightsep", \\ % "outerleftsep" &:= -"leftsep", & "outerrightsep" &:= -"rightsep". % \end{align*} % % \item[trim] Specify the margin to be trimmed. The value can be "l", "r", and % "lr", "rl". This helps the slash line exceeds the boundary when "@{}" column % specifier is used. % % Note: "trim=l" has the same effect as "leftsep=0pt", and "trim=r" has the % same effect as "rightsep=0pt". % % \item[font] Specify the font of the cell. % % "\diagbox[font=\footnotesize\itshape]{Small}{Italic}"\quad % \begin{tabular}{|c|} \hline % \diagbox[font=\footnotesize\itshape]{Small}{Italic} \\ \hline % \end{tabular} % % \item[linewidth] Specify the line width of the diagonal lines. % \item[linecolor] Specify the line color of the diagonal lines. (\pkg{color} % or \pkg{xcolor} is needed.) % % "\diagbox[linewidth=2pt,linecolor=blue]{AAA}{BBB}"\quad % \begin{tabular}{|c|} \hline % \diagbox[linewidth=2pt,linecolor=blue]{AAA}{BBB} \\ \hline % \end{tabular} % \end{description} % % Here is a more complex example to show the usage of the options: % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|@{}l|c|c|r@{}|} % \hline % \diagbox[width=5em,trim=l]{Time}{Day} & Mon & Tue & Wed\\ % \hline % Morning & used & used & used\\ % \hline % Afternoon & & used & \diagbox[dir=SW,height=2em,trim=r]{A}{B} \\ % \hline % \end{tabular} % \end{Example} % % \bigskip % What's more, you can use "\\" to break lines in "\diagbox". Manual setting % of the height of the head may be needed. For example, % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|c|} % \hline % \diagbox[height=3\line]{line\\heads}{column\\heads} \\ % \hline % \end{tabular} % \end{Example} % % \subsection{Compatibility with \pkg{slashbox}} % % \pkg{diagbox} package emulates \pkg{slashbox} and also prevents % \pkg{slashbox} to be loaded. % % \pkg{diagbox} package provides "\slashbox" and "\backslashbox" which syntax % similar to \pkg{slashbox} package. However, the results of the two packages % are a little different. These two commands are for compatibility only, it is % better to use "\diagbox" instead for new documents. % % \DescribeMacro{\backslashbox} % "\backslashbox" works as "\diagbox", but it takes two optional arguments to % specify the "width" and "trim" options. % % \DescribeMacro{\slashbox} % "\slashbox" works as "\diagbox[dir=SW]", and takes two optional arguments to % specify the "width" and "trim" options. % % For example,\\ % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|c|c|c|} \hline % \backslashbox[2cm]{num}{alpha} % & A & B \\\hline % 1 & A1 & B1 \\\hline % 2 & A2 & B2 \\\hline % \end{tabular} % \end{SideBySideExample} % % % \section{Known issues and TODO} % % Known issues: % \begin{itemize} % \item The result of "\slashbox" and "\backslashbox" is different with % \pkg{slashbox} package. The algorithms to calculate the width and height are % different; and the results of the second optional argument of "\slashbox" % (i.e. "trim" key in "\diagbox") in the two packages are differernt. % % This is not a bug. Usually the width calculated by \pkg{diagbox} is more % safe than \pkg{slashbox}. % % \item For a triple box (a table head with two diagonal lines), the first % argument must not be too wide and the third argument must not be too high. % Otherwise, the layout algorithm cannot calculate the proper width and height % of the table head, and a warning will be issued. (Thanks to Frank Mittelbach.) % % \item % The cell with "\diagbox" should be the widest one of the column. Otherwise % the slash line cannot exceeds the boundary. For example,\\[1ex] % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|c|} \hline % \diagbox{A}{B} \\\hline % Very long term \\\hline % \end{tabular} % \end{SideBySideExample} % \\[1ex] % This can be solved by setting a wider "width" option of "\diagbox" manually. % \end{itemize} % % % \title[]{\hypertarget{Chinese}{\pkg{diagbox} 宏包(\fileversion)} % \makebox[0pt][l]{\hspace{3cm}\large % \hyperlink{English}{$\Rightarrow$ \textsf{English Version}}}\\ % 制做斜线表头} % \author{刘海洋 \\ \path{leoliu.pku@gmail.com}} % \date{\filedate} % % \maketitle % % % \section{简介} % % \pkg{diagbox} 设计用来代替旧的 \pkg{slashbox} 宏包\footnote{作者 Koichi % Yasuoka(安岡孝一)与 Sato Toru(佐藤徹)。宏包见 % \url{CTAN://macros/latex/contrib/slashbox/slashbox.sty}。}。编写这个宏包的缘 % 起是 \pkg{slashbox} 因为缺少明确的自由许可信息,被 \TeX\ Live 排除。这个宏包 % 是在 LPPL 协议下发行的。 % % \pkg{diagbox} 是 \pkg{slashbox} 宏包的一个现代的版本。它采用了新的 key-value % 式语法参数,去除了 \pkg{slashbox} 原有的一些长度限制,并调用 \pkg{pict2e} 宏 % 包画斜线;特别还添加了绘制两条斜线的表头的新功能。 % % 作为 \pkg{slashbox} 的代替,\pkg{diagbox} 除了提供自己的新命令,也提供了 % \pkg{slashbox} 原有的两个命令,语法不变,编译结果略有区别。 % % \pkg{diagbox} 依赖 \eTeX{} 扩展(这在目前总是可用的),依赖 \pkg{pict2e}、 % \pkg{keyval}、\pkg{calc} 和 \pkg{fp} 宏包。 % % \section{用法说明} % % \subsection{基本用法} % % 要使用本宏包,首先在导言区调用: % \begin{Verbatim} % \usepackage{diagbox} % \end{Verbatim} % % \DescribeMacro{\diagbox} % "\diagbox" 是宏包提供的主要命令。它可以带有两个必选参数,表示要生成斜线表头的 % 两部分内容。默认斜线是从西北到东南方向的。 % % 例如:\\ % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|l|ccc|} % \hline % \diagbox{Time}{Day} & Mon & Tue & Wed \\ % \hline % Morning & used & used & \\ % Afternoon & & used & used \\ % \hline % \end{tabular} % \end{SideBySideExample} % \medskip % % \changes{v2.0}{2011/11/22}{增加有三部分、双斜线的表头格式。} % "\diagbox" 也可以接受三个参数,这样就会生成带有两条斜线的表头,例如: % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|l|ccc|} % \hline % \diagbox{Time}{Room}{Day} & Mon & Tue & Wed \\ % \hline % Morning & used & used & \\ % Afternoon & & used & used \\ % \hline % \end{tabular} % \end{Example} % % \subsection{更多参数设置} % % "\diagbox" 还可以在前面带一个可选参数,里面用 key-value 的语法设置宽度、方向 % 等更多的选项: % \begin{description} % \item[width] 明确指定盒子的总宽度。如果省略,则会自动计算能够放下所有内容的 % 宽度。 % \item[height] 明确指定盒子的总高度。 % \item[dir] 指定斜线方向。可以取 "NW"(西北)、"NE"(东北)、"SW"(西南)、 % "SE"(东南)四种方向。在只有一条斜线的表头中,"NE" 与 "SW"、 "SE" 与 "NW" 是 % 等价的。斜线方向的默认值是 "NW"。 % % "\diagbox[dir="\meta{方向}"]{A}{B}" 在表格中的效果:\\ % \begin{tabular}{ll@{\qquad}ll} % "NW" 或 "SE":& % \begin{tabular}{|c|} \hline \diagbox[dir=SE]{A}{B} \\\hline \end{tabular} & % "SW" 或 "NE":& % \begin{tabular}{|c|} \hline \diagbox[dir=NE]{A}{B} \\\hline \end{tabular} % \end{tabular} % % "\diagbox[dir="\meta{方向}"]{A}{M}{B}" 在表格中的效果:\\ % \begin{tabular}{*4{ll@{\qquad}}} % "NW"& % \begin{tabular}{|c|} \hline \diagbox[dir=NW]{A}{M}{B} \\\hline \end{tabular}& % "NE"& % \begin{tabular}{|c|} \hline \diagbox[dir=NE]{A}{M}{B} \\\hline \end{tabular}& % "SW"& % \begin{tabular}{|c|} \hline \diagbox[dir=SW]{A}{M}{B} \\\hline \end{tabular}& % "SE"& % \begin{tabular}{|c|} \hline \diagbox[dir=SE]{A}{M}{B} \\\hline \end{tabular} % \end{tabular} % % \item[innerwidth] 设置盒子中内容的宽度。"innerwidth" 选项可以与表格的列宽度 % 一起设置并保持一致。如: % \begin{Example} % \begin{tabular}{|p{2cm}|} \hline % \diagbox[innerwidth=2cm]{A}{B} \\ \hline % \end{tabular} % \end{Example} % % \item[innerleftsep, innerrightsep] 设置内间距,即内容盒子与斜线盒子边界之间 % 的距离。我们有关系式: % \[ % "innerleftsep" + "innerwidth" + "innerrightsep" = "width". % \] % 例如: % \begin{Example} % \begin{tabular}{|c|} \hline % \diagbox[innerleftsep=.5cm,innerrightsep=0pt]{A}{B} \\ \hline % \end{tabular} % \end{Example} % % \item[outerleftsep, outerrightsep] 设置外间距,即斜线盒子边界到表格单元格边 % 界的距离。由于斜线是沿单元格画出而非斜线盒子本身画出,斜线通常会伸出斜线盒子 % 之外,此距离为负数,并满足如下关系式: % \begin{align*} % "outerleftsep" + "LEFTtabcolsep" &= 0\,\mathrm{pt}, \\ % "outerrightsep" + "RIGHTtabcolsep" &= 0\,\mathrm{pt}. % \end{align*} % 其中 "LEFTtabcolsep" 与 "RIGHTtabcolsep" 是表格竖线与表格内容(斜线例子边 % 界)之间的距离。例如: % \begin{Example} % \begin{tabular}{|r@{\hspace{20pt}}|l|} \hline % \diagbox[outerrightsep=-20pt]{A}{B} & C \\ \hline % AABB & CC \\ \hline % \end{tabular} % \end{Example} % % \item[leftsep, rightsep] 同时设置左右内外间距,满足关系式: % \begin{align*} % "innerleftsep" &:= "leftsep", & "innerrightsep" &:= "rightsep", \\ % "outerleftsep" &:= -"leftsep", & "outerrightsep" &:= -"rightsep". % \end{align*} % % \item[trim] 设置左边界或右边界不计算额外的空白,可以取值为 "l", "r", "lr" 或 % "rl"。这个选项在列格式包含 "@{}" 时将会有用。 % % 注:"trim=l" 与 "leftsep=0pt" 效果相同,而 "trim=r" 与 "rightsep=0pt" 效果相 % 同。 % % \item[font] 设置单元格字体。 % % "\diagbox[font=\footnotesize\itshape]{Small}{Italic}"\quad % \begin{tabular}{|c|} \hline % \diagbox[font=\footnotesize\itshape]{Small}{Italic} \\ \hline % \end{tabular} % % \item[linewidth] 设置斜线宽度。 % \item[linecolor] 设置斜线颜色。(需要自行载入 \pkg{color} 或 \pkg{xcolor} 宏 % 包。) % % "\diagbox[linewidth=2pt,linecolor=blue]{AAA}{BBB}"\quad % \begin{tabular}{|c|} \hline % \diagbox[linewidth=2pt,linecolor=blue]{AAA}{BBB} \\ \hline % \end{tabular} % \end{description} % % \changes{v2.0}{2011/11/23}{变更 "trim" 选项的行为,去掉了使用 "trim" 选项时 % 内部的间距。这与 \pkg{slashbox} 行为不同。} % 一个更复杂的例子: % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|@{}l|c|c|r@{}|} % \hline % \diagbox[width=5em,trim=l]{Time}{Day} & Mon & Tue & Wed\\ % \hline % Morning & used & used & used\\ % \hline % Afternoon & & used & \diagbox[dir=SW,height=2em,trim=r]{A}{B} \\ % \hline % \end{tabular} % \end{Example} % \bigskip % % 此外,"\diagbox" 的表头内容还可以用 "\\" 手工换行。此时通常需要对自动计算的 % 表头高度进行手工调整。例如: % \begin{Example}[frame=single,numbers=left] % \begin{tabular}{|c|} % \hline % \diagbox[height=3\line]{line\\heads}{column\\heads} \\ % \hline % \end{tabular} % \end{Example} % % \subsection{对 \pkg{slashbox} 宏包的兼容性} % % 在使用 \pkg{diagbox} 宏包时,会模拟 \pkg{slashbox} 宏包的功能,并禁止 % \pkg{slashbox} 再被调用。 % % \pkg{diagbox} 宏包提供了与 \pkg{slashbox} 大致相同的 "\slashbox" 与 % "\backslashbox" 两个命令。 "\slashbox" 与 "\backslashbox" 的语法来自 % \pkg{slashbox} 宏包,排版效果略有区别。这两个命令仅在旧文档中作为兼容命令使 % 用。实际中使用 "\diagbox" 更为方便。 % % \DescribeMacro{\backslashbox} % "\backslashbox" 基本功能与 "\diagbox" 类似。它带有两个可选参数,分别表示 % "\diagbox" 中的 "width" 与 "trim" 选项。 % % \DescribeMacro{\slashbox} % "\slashbox" 基本功能与 "\diagbox[dir=SW]" 类似。它也带有两个可选参数,表示 % "\diagbox" 中的 "width" 和 "tirm" 选项。 % % 例如:\\ % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|c|c|c|} \hline % \backslashbox[2cm]{num}{alpha} % & A & B \\\hline % 1 & A1 & B1 \\\hline % 2 & A2 & B2 \\\hline % \end{tabular} % \end{SideBySideExample} % % \section{已知问题和未来版本} % % 已知问题: % \begin{itemize} % \item "\slashbox" 与 "\backslashbox" 命令的效果与在 \pkg{slashbox} 宏包中不 % 同。两个宏包在计算盒子宽度和高度时,使用了不同的算法;同时,在处理 % "\slashbox" 第二个可选参数(即 "\diagbox" 的 "trim" 键)时,使用的方式也不一 % 样。 % % 这不是 bug。通常 \pkg{diagbox} 计算出的宽度比 \pkg{slashbox} 的结果更安全一 % 些。 % % \item 有两条斜线的三部分表头,其所采用的自动布局算法是受限的。特别是,最左的 % 部分不能过宽,最右的部分不能过高,否则将无法计算出合理的结果,宏包会发出警 % 告。(感谢 Frank Mittelbach 指出该问题。) % % \item % "\diagbox" 生成的单元格必须是表列中最宽的一个。如果不能达到最宽,则画出的斜 % 线不能保证在正确的位置。例如:\\[1ex] % \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.45\linewidth] % \begin{tabular}{|c|} \hline % \diagbox{A}{B} \\\hline % Very long term \\\hline % \end{tabular} % \end{SideBySideExample} % \\[1ex] % 此时可以手工设置较宽的 "\diagbox" 的 "width" 选项,解决此问题。 % \end{itemize} % % \StopEventually{} % % % \clearpage % \section{Implementation / 代码实现} % % \iffalse %<*package> % \fi % % \subsection{实现依赖的工具包} % % 使用 key-value 界面。 % \begin{macrocode} \RequirePackage{keyval} % \end{macrocode} % 绘图依赖 \pkg{pict2e} 宏包。 % \begin{macrocode} \RequirePackage{pict2e} % \end{macrocode} % \changes{v2.2}{2016/12/28}{避免 \pkg{fp} 包的 \texttt{nomessages} 选项在使用 % \pkg{catoptions} 包时冲突} % 长度计算 \pkg{calc} 宏包。 % \changes{v2.2}{2016/12/28}{使用 \pkg{calc} 包计算选项参数,以支持 % \cs{widthof} 等命令。} % \begin{macrocode} \RequirePackage{calc} % \end{macrocode} % 内部控制 \pkg{array} 宏包。 % \begin{macrocode} \RequirePackage{array} % \end{macrocode} % % % \subsection{资源分配} % % 分配用到的盒子寄存器。它们分别对应于 "\diagbox" 三个必选参数的内容。 % \begin{macrocode} \newbox\diagbox@boxa \newbox\diagbox@boxb \newbox\diagbox@boxm % \end{macrocode} % 分配长度变量。 % \begin{macrocode} \newdimen\diagbox@wd \newdimen\diagbox@ht \newdimen\diagbox@insepl \newdimen\diagbox@insepr \newdimen\diagbox@outsepl \newdimen\diagbox@outsepr % \end{macrocode} % % \begin{macrocode} \def\diagbox@clear{% \diagbox@wd=\z@ \diagbox@ht=\z@ \diagbox@insepl=\tabcolsep \diagbox@insepr=\tabcolsep \diagbox@outsepl=-\tabcolsep \diagbox@outsepr=-\tabcolsep } % \end{macrocode} % % \subsection{命令选项定义} % % 下面定义 "\diagbox" 的键值选项。 % % \changes{v2.1}{2014/07/03}{允许在 \texttt{width} 和 \texttt{height} 的命令选项 % 中写表达式计算长度。} % \changes{v2.1}{2016/02/24}{允许在 \texttt{height} 选项中使用 % \texttt{\textbackslash line} 表示行高。} % 斜线盒子的总宽度。 % \begin{macrocode} \define@key{diagbox}{width}{% \unless\ifdim\diagbox@wd=\z@ \PackageWarning{diagbox}% {You should not set width/innerwidth option more than once.}% \fi \setlength{\diagbox@wd}{#1}} % \end{macrocode} % 斜线盒子的总高度,参数中可使用 "\line" 表示行高。 % \begin{macrocode} \define@key{diagbox}{height}{% \let\diagbox@save@line\line \def\line{\normalbaselineskip}% \setlength{\diagbox@ht}{#1}% \let\line\diagbox@save@line} % \end{macrocode} % % \changes{v2.1}{2014/08/15}{盒子内容与斜线框距离 \texttt{innerleftsep}, % \texttt{innerrightsep} 命令选项。} % 盒子内容与斜线框左右的距离。 % \begin{macrocode} \define@key{diagbox}{innerleftsep}{% \setlength{\diagbox@insepl}{#1}} \define@key{diagbox}{innerrightsep}{% \setlength{\diagbox@insepr}{#1}} % \end{macrocode} % % \changes{v2.1}{2016/02/24}{盒子内容宽度 \texttt{innerwidth} 命令选项。} % 设置盒子内容的宽度(与列格式 "p{宽度}" 对应)。盒子内容宽度加上盒子与斜线框 % 左右距离之和应为斜线盒子总宽度,即有 % \[ % "innerleftsep" + "innerwidth" + "innerrightsep" = "width". % \] % "innerwidth" 选项将通过设置盒子总宽度,维护上面的关系式。 % \begin{macrocode} \define@key{diagbox}{innerwidth}{% \unless\ifdim\diagbox@wd=\z@ \PackageWarning{diagbox}% {You should not set width/innerwidth option more than once.}% \fi \setlength{\diagbox@wd}{#1+\diagbox@insepl+\diagbox@insepr}} % \end{macrocode} % % \changes{v2.1}{2014/08/15}{斜线盒子与表格单元边框距离 \texttt{outerleftsep}, % \texttt{outerrightsep} 命令选项。} % 斜线盒子与表格单元边框距离。该外部间距应为实际表列内容与列分隔线之间距离的相 % 反数,以此保证斜线与表格竖线能相接,即应输入参数保证 % \begin{align*} % "outerleftsep" + "LEFTtabcolsep" &= 0\,\mathrm{pt}, \\ % "outerrightsep" + "RIGHTtabcolsep" &= 0\,\mathrm{pt}. % \end{align*} % \begin{macrocode} \define@key{diagbox}{outerleftsep}{% \setlength{\diagbox@outsepl}{#1}} \define@key{diagbox}{outerrightsep}{% \setlength{\diagbox@outsepr}{#1}} % \end{macrocode} % % \changes{v2.1}{2014/08/15}{左右边距 \texttt{leftsep}, \texttt{rightsep} 命令 % 选项。} % 设置左右边距,它将同时设置盒子内容与斜线框的内部间距,以及斜线盒子与表格单元 % 边框的外部间距。并保持关系: % \begin{align*} % "innerleftsep" &:= "leftsep", & "innerrightsep" &:= "rightsep", \\ % "outerleftsep" &:= -"leftsep", & "outerrightsep" &:= -"rightsep". % \end{align*} % \begin{macrocode} \define@key{diagbox}{leftsep}{% \setlength{\diagbox@insepl}{#1}% \setlength{\diagbox@outsepl}{(#1)*-1}} \define@key{diagbox}{rightsep}{% \setlength{\diagbox@insepr}{#1}% \setlength{\diagbox@outsepr}{(#1)*-1}} % \end{macrocode} % % 盒子计算边界时是否忽略左右的空白。"trim=l" 效果等同于 "leftsep=0pt";"trim=r" % 效果等同于 "rightsep=0pt"。 % \begin{macrocode} \define@key{diagbox}{trim}{% \@tfor\@reserveda:=#1\do{% \ifcsname diagbox@insep\@reserveda\endcsname \setlength{\csname diagbox@insep\@reserveda\endcsname}{\z@}% \setlength{\csname diagbox@outsep\@reserveda\endcsname}{\z@}% \else \PackageError{diagbox}{Unknown trim option `#1'.}{l, r, lr and rl are supported.}% \fi}} % \end{macrocode} % % 盒子的方向。 % \begin{macrocode} \define@key{diagbox}{dir}{% \def\diagbox@dir{#1}% \unless\ifcsname diagbox@dir@#1\endcsname \PackageError{diagbox}{Unknown direction `#1'.}{NW, NE, SW, SE are supported.}% \def\diagbox@dia{NW}% \fi} \let\diagbox@dir@SE\relax \let\diagbox@dir@SW\relax \let\diagbox@dir@NE\relax \let\diagbox@dir@NW\relax % \end{macrocode} % % \changes{v2.1}{2014/07/03}{增加命令选项 \texttt{linewidth}, \texttt{linecolor} % 设置斜线宽度与颜色。} % 斜线宽度与颜色。 % \begin{macrocode} \define@key{diagbox}{linewidth}{% \setlength{\@tempskipa}{#1}% \linethickness{\@tempskipa}} \define@key{diagbox}{linecolor}{% \def\diagbox@setlinecolor{\color{#1}}} \let\diagbox@setlinecolor\empty % \end{macrocode} % % \changes{v2.1}{2014/07/03}{增加命令选项 \texttt{font} 支持设置内容字体。} % 设置内容字体。 % \begin{macrocode} \define@key{diagbox}{font}{% \def\diagbox@font{#1}} \let\diagbox@font\empty % \end{macrocode} % % \subsection{绘制斜线盒子} % % \begin{macro}{\diagbox@pict} % 这是带斜线的盒子本身。由一个 "picture" 环境实现。 % \begin{macrocode} \def\diagbox@pict{% \unitlength\p@ \begin{picture} (\strip@pt\dimexpr\diagbox@wd+\diagbox@outsepl+\diagbox@outsepr\relax,\strip@pt\diagbox@ht) (\strip@pt\dimexpr-\diagbox@outsepl\relax,0) \@nameuse{diagbox@\diagbox@part @pict@\diagbox@dir} \end{picture}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@double@pict@SE} % 方向为 "SE" 的斜线盒子内容。 % \begin{macrocode} \def\diagbox@double@pict@SE{% \put(0,0) {\makebox(0,0)[bl]{\box\diagbox@boxa}} \put(\strip@pt\diagbox@wd,\strip@pt\diagbox@ht) {\makebox(0,0)[tr]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,\strip@pt\diagbox@ht)(\strip@pt\diagbox@wd,0)} % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@double@pict@NW} % 方向 "NW" 与 "SE" 相同。 % \begin{macrocode} \let\diagbox@double@pict@NW\diagbox@double@pict@SE % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@double@pict@NE} % 方向为 "NE" 的斜线盒子内容。 % \begin{macrocode} \def\diagbox@double@pict@NE{% \put(0,\strip@pt\diagbox@ht) {\makebox(0,0)[tl]{\box\diagbox@boxa}} \put(\strip@pt\diagbox@wd,0) {\makebox(0,0)[br]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,0)(\strip@pt\diagbox@wd,\strip@pt\diagbox@ht)} % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@double@pict@NE} % 方向 "SW" 与 "NE" 相同。 % \begin{macrocode} \let\diagbox@double@pict@SW\diagbox@double@pict@NE % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@double} % \changes{v2.0}{2011/11/22}{在使用 "trim" 选项时去掉内容与盒子边界的间距。这 % 与 \pkg{slashbox} 的行为不同。} % 分成两部分的盒子。三个参数,分别为 key-value 格式的可选项、左半边内容、右半边 % 内容。这里的主要工作是读入参数并计算斜线盒子的大小。 % % 这里自动计算斜线盒子大小的算法为:斜线盒子的宽度取两个子盒宽度较大值的二倍, % 而高度则直接取两个子盒的总高度。 % \begin{macrocode} \def\diagbox@double#1#2#3{% \begingroup \diagbox@clear \def\diagbox@part{double}% \setkeys{diagbox}{dir=NW,#1}% \setbox\diagbox@boxa=\hbox{% \begin{tabular}{@{\hspace{\diagbox@insepl}}>{\diagbox@font}l@{}} #2 \end{tabular}}% \setbox\diagbox@boxb=\hbox{% \begin{tabular}{@{}>{\diagbox@font}r@{\hspace{\diagbox@insepr}}} #3 \end{tabular}}% \ifdim\diagbox@wd=\z@ \ifdim\wd\diagbox@boxa>\wd\diagbox@boxb \diagbox@wd=\dimexpr2\wd\diagbox@boxa+\diagbox@insepl+\diagbox@insepr\relax \else \diagbox@wd=\dimexpr2\wd\diagbox@boxb+\diagbox@insepl+\diagbox@insepr\relax \fi \fi \ifdim\diagbox@ht=\z@ \diagbox@ht=\dimexpr\ht\diagbox@boxa+\dp\diagbox@boxa+\ht\diagbox@boxb+\dp\diagbox@boxb\relax \fi $\vcenter{\hbox{\diagbox@pict}}$% \endgroup} % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@triple@setbox@NW} % \begin{macrocode} \def\diagbox@triple@setbox@NW#1#2#3{% \setbox\diagbox@boxa=\hbox{% \begin{tabular}{@{\hspace{\diagbox@insepl}}>{\diagbox@font}l@{}} #1 \end{tabular}}% \setbox\diagbox@boxm=\hbox{% \begin{tabular}{@{\hspace{\diagbox@insepl}}>{\diagbox@font}l@{}} #2 \end{tabular}}% \setbox\diagbox@boxb=\hbox{% \begin{tabular}{@{}>{\diagbox@font}r@{\hspace{\diagbox@insepr}}} #3 \end{tabular}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@triple@setbox@SW} % \begin{macrocode} \let\diagbox@triple@setbox@SW\diagbox@triple@setbox@NW % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@triple@setbox@SE} % \begin{macrocode} \def\diagbox@triple@setbox@SE#1#2#3{% \setbox\diagbox@boxa=\hbox{% \begin{tabular}{@{\hspace{\diagbox@insepl}}>{\diagbox@font}l@{}} #1 \end{tabular}}% \setbox\diagbox@boxm=\hbox{% \begin{tabular}{@{}>{\diagbox@font}r@{\hspace{\diagbox@insepr}}} #2 \end{tabular}}% \setbox\diagbox@boxb=\hbox{% \begin{tabular}{@{}>{\diagbox@font}r@{\hspace{\diagbox@insepr}}} #3 \end{tabular}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\diagbox@triple@setbox@NE} % \begin{macrocode} \let\diagbox@triple@setbox@NE\diagbox@triple@setbox@SE % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@triple@pict@NW} % \begin{macrocode} \def\diagbox@triple@pict@NW{% \put(0,0) {\makebox(0,0)[bl]{\box\diagbox@boxa}} \put(0,\y) {\makebox(0,0)[tl]{\box\diagbox@boxm}} \put(\x,\y) {\makebox(0,0)[tr]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,\yym)(\x,0) \Line(\xm,\y)(\x,0)} % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@triple@pict@NE} % \begin{macrocode} \def\diagbox@triple@pict@NE{% \put(0,\y) {\makebox(0,0)[tl]{\box\diagbox@boxa}} \put(\x,\y) {\makebox(0,0)[tr]{\box\diagbox@boxm}} \put(\x,0) {\makebox(0,0)[br]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,0)(\xxm,\y) \Line(0,0)(\x,\yym)} % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@triple@pict@SW} % \begin{macrocode} \def\diagbox@triple@pict@SW{% \put(0,\y) {\makebox(0,0)[tl]{\box\diagbox@boxa}} \put(0,0) {\makebox(0,0)[bl]{\box\diagbox@boxm}} \put(\x,0) {\makebox(0,0)[br]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,\ym)(\x,\y) \Line(\xm,0)(\x,\y)} % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@triple@pict@SE} % \begin{macrocode} \def\diagbox@triple@pict@SE{% \put(0,0) {\makebox(0,0)[bl]{\box\diagbox@boxa}} \put(\x,0) {\makebox(0,0)[br]{\box\diagbox@boxm}} \put(\x,\y) {\makebox(0,0)[tr]{\box\diagbox@boxb}} \diagbox@setlinecolor \Line(0,\y)(\xxm,0) \Line(0,\y)(\x,\ym)} % \end{macrocode} % \end{macro} % % % \begin{macro}{\diagbox@triplebox} % \changes{v2.0}{2011/11/22}{新增三部分双斜线的盒子} % \changes{v2.3}{2020/02/09}{检测二次方程无解、异常解的情形} % 分成三部分的盒子。四个参数,分别为 key-value 格式的可选项、左半边内容、中间 % 内容、右半边内容。 % \begin{macrocode} \def\diagbox@triple#1#2#3#4{% \begingroup \diagbox@clear \def\diagbox@part{triple}% \setkeys{diagbox}{dir=NW,#1}% \@nameuse{diagbox@triple@setbox@\diagbox@dir}{#2}{#3}{#4}% % \end{macrocode} % 在宏包最后定义,需要返回 "\x", "\xm", "\xxm", "\y", "\ym" 和 "\yym"。 % \begin{macrocode} \diagbox@solve@equations $\vcenter{\hbox{\diagbox@pict}}$% \endgroup} % \end{macrocode} % \end{macro} % % \subsection{用户命令} % % \begin{macro}{\diagbox} % \changes{v2.0}{2011/11/22}{判断参数个数,选择两部分或三部分盒子。} % 主要的用户命令。判断使用两部分还是三部分的盒子。 % \begin{macrocode} \newcommand\diagbox[3][]{% \@ifnextchar\bgroup {\diagbox@triple{#1}{#2}{#3}}{\diagbox@double{#1}{#2}{#3}}} % \end{macrocode} % \end{macro} % % 以下代码用来模拟 \pkg{slashbox} 宏包的功能。 % % 禁止读入 \pkg{slashbox}。 % \begin{macrocode} \expandafter\xdef\csname ver@slashbox.\@pkgextension\endcsname{9999/99/99} % \end{macrocode} % % % \begin{macro}{\slashbox} % 模拟 "\slashbox"。 % \begin{macrocode} \def\slashbox{% \def\diagbox@slashbox@options{dir=SW,}% \slashbox@} % \end{macrocode} % \end{macro} % % % \begin{macro}{\backslashbox} % 模拟 "\backslashbox"。 % \begin{macrocode} \def\backslashbox{% \def\diagbox@slashbox@options{dir=NW,}% \slashbox@} % \end{macrocode} % \end{macro} % % % \begin{macro}{\slashbox@} % \begin{macrocode} \newcommand\slashbox@[1][]{% \ifx\relax#1\relax\else \edef\diagbox@slashbox@options{% \unexpanded\expandafter{\diagbox@slashbox@options}% \unexpanded{width=#1,}}% \fi \slashbox@@} % \end{macrocode} % \end{macro} % % % \begin{macro}{\slashbox@@} % \begin{macrocode} \newcommand\slashbox@@[3][]{% \edef\diagbox@slashbox@options{% \unexpanded\expandafter{\diagbox@slashbox@options}% \unexpanded{trim=#1,}}% \expandafter\diagbox\expandafter[\diagbox@slashbox@options]{#2}{#3}} % \end{macrocode} % \end{macro} % % \changes{v2.4}{2020/02/28}{利用 \pkg{l3fp} 解方程组。} % % \subsection{解方程组} % % 这里计算双斜线盒子宽、高的算法是简单而直观的。如下图所示,将 A、M、B 三个子盒 % 子分别放在斜线盒的三个角后,斜线正好使 M 盒、A 或 B 盒、斜线盒的一角三点共 % 线。 % \[ % \tabcolsep=0pt % \linespread{1}\selectfont % \begin{tabular}{|c|}\hline % \diagbox{\fbox{A}}{\fbox{M}}{\fbox{B}}\\ \hline % \end{tabular} % \] % 在 A、M、B 三个盒子内容确定后,斜线盒的宽、高即可通过相似三角形的比例关系求 % 解。设斜线盒的宽、高为 $x$, $y$,而 A、M、B 盒的宽、高分别为 $(x_a, y_a)$, % $(x_m, y_m)$, $(x_b, y_b)$。则有: % \begin{align*} % \frac{x}{x_a} &= \frac{y - y_m}{y - y_m - y_a}, \\ % \frac{y}{y_b} &= \frac{x - x_m}{x - x_m - x_b}. % \end{align*} % 该方程组通常可化简为一个一元二次方程求解,两组共轭根中可以只需要较大的一组。 % 通过 Mathematica 软件,容易得到方程组的解为: % \begin{align*} % x & = \frac{u + v \pm \sqrt{\Delta}} {2(t - y_b)}, \\ % y & = \frac{u - v \mp \sqrt{\Delta}} {2(x_a - s)}, \\ % \Delta & := (u + v)^2 + 4 x_a (t - y_b) \bigl(x_m (y_b - y_m) - x_b y_m\bigr), \\ % u & := x_a y_m - x_m y_b, \\ % v & := st - x_a y_b, \\ % s & := x_b + x_m, \\ % t & := y_a + y_m. % \end{align*} % 但须注意上面的方程组并非总有正的实根,经过简单的代数分析可知,要给出几何直观 % 的可行解(正实根),需要同时满足以下条件: % \begin{align*} % x_a &< x_m + x_b, \\ % y_b &< y_m + y_a. % \end{align*} % 该条件需要在计算中予以检查。 % % \begin{macro}{\diagbox@solve@equations} % 如果 \pkg{expl3} 环境可用,就使用 \pkg{l3fp} 计算,否则使用 \pkg{fp} 包。 % \begin{macrocode} \ifcsname\detokenize{fp_eval:n}\endcsname \csname fi\endcsname \ExplSyntaxOn %<@@=diagbox> \cs_new_protected:Npn \@@_solve_equations: { % \end{macrocode} % 取长宽。 % \begin{macrocode} \fp_set:Nn \l_@@_xa_fp { \dim_to_fp:n { \wd \diagbox@boxa } } \fp_set:Nn \l_@@_ya_fp { \dim_to_fp:n { \ht \diagbox@boxa + \dp \diagbox@boxa } } \fp_set:Nn \l_@@_xb_fp { \dim_to_fp:n { \wd \diagbox@boxb } } \fp_set:Nn \l_@@_yb_fp { \dim_to_fp:n { \ht \diagbox@boxb + \dp \diagbox@boxb } } \fp_set:Nn \l_@@_xm_fp { \dim_to_fp:n { \wd \diagbox@boxm } } \fp_set:Nn \l_@@_ym_fp { \dim_to_fp:n { \ht \diagbox@boxm + \dp \diagbox@boxm } } \fp_set:Nn \l_@@_s_fp { \l_@@_xb_fp + \l_@@_xm_fp } \fp_set:Nn \l_@@_t_fp { \l_@@_ya_fp + \l_@@_ym_fp } % \end{macrocode} % 如果宽度和长度都被指定了,就不需要列方程组求解。 % \begin{macrocode} \fp_set_eq:NN \l_@@_delta_fp \c_nan_fp \dim_compare:nNnTF \diagbox@wd = \c_zero_dim { \@@_calculate_width: } { \fp_set:Nn \l_@@_x_fp { \dim_to_fp:n { \diagbox@wd } } } \dim_compare:nNnTF \diagbox@ht = \c_zero_dim { \@@_calculate_height: } { \fp_set:Nn \l_@@_y_fp { \dim_to_fp:n { \diagbox@ht } } } \edef \x { \fp_use:N \l_@@_x_fp } \edef \y { \fp_use:N \l_@@_y_fp } \edef \xm { \fp_use:N \l_@@_xm_fp } \edef \ym { \fp_use:N \l_@@_ym_fp } \edef \xxm { \fp_eval:n { \l_@@_x_fp - \l_@@_xm_fp } } \edef \yym { \fp_eval:n { \l_@@_y_fp - \l_@@_ym_fp } } } % \end{macrocode} % 检查可行解条件,解二次方程。这里对于无正实根的情形,会给出一个宽松的值作为斜 % 线盒子的宽高: % \begin{align*} % x &= 2 \max(x_a + x_m, x_b + x_m),\\ % y &= 2 \max(y_a + y_m, y_b + y_m). % \end{align*} % \begin{macrocode} \cs_new_protected:Npn \@@_calculate_width: { \fp_zero:N \l_@@_x_fp \fp_compare:nNnT \l_@@_yb_fp < \l_@@_t_fp { \@@_calculate_coefficient: \fp_if_nan:nF { \l_@@_sqrt_fp } { \fp_set:Nn \l_@@_x_fp { ( \l_@@_u_fp + \l_@@_v_fp + \l_@@_sqrt_fp ) / ( 2 ( \l_@@_t_fp - \l_@@_yb_fp ) ) } } } \fp_compare:nNnF \l_@@_x_fp > \c_zero_fp { \fp_set:Nn \l_@@_x_fp { 2 ( max( \l_@@_xa_fp , \l_@@_xb_fp ) + \l_@@_xm_fp ) } \msg_warning:nnxx { diagbox } { calculate-error } { width } { \fp_use:N \l_@@_x_fp } } \diagbox@wd = \fp_to_dim:N \l_@@_x_fp \scan_stop: } \cs_new_protected:Npn \@@_calculate_height: { \fp_zero:N \l_@@_y_fp \fp_compare:nNnT \l_@@_xa_fp < \l_@@_s_fp { \@@_calculate_coefficient: \fp_if_nan:nF { \l_@@_sqrt_fp } { \fp_set:Nn \l_@@_y_fp { ( \l_@@_u_fp - \l_@@_v_fp - \l_@@_sqrt_fp ) / ( 2 ( \l_@@_xa_fp - \l_@@_s_fp ) ) } } } \fp_compare:nNnF \l_@@_y_fp > \c_zero_fp { \fp_set:Nn \l_@@_y_fp { 2 ( max( \l_@@_ya_fp , \l_@@_yb_fp ) + \l_@@_ym_fp ) } \msg_warning:nnxx { diagbox } { calculate-error } { height } { \fp_use:N \l_@@_y_fp } } \diagbox@ht = \fp_to_dim:N \l_@@_y_fp \scan_stop: } \cs_new_protected:Npn \@@_calculate_coefficient: { \fp_if_nan:nT { \l_@@_delta_fp } { \@@_calculate_coefficient_aux: } } \cs_new_protected:Npn \@@_calculate_coefficient_aux: { \fp_set:Nn \l_@@_u_fp { \l_@@_xa_fp * \l_@@_ym_fp - \l_@@_xm_fp * \l_@@_yb_fp } \fp_set:Nn \l_@@_v_fp { \l_@@_s_fp * \l_@@_t_fp - \l_@@_xa_fp * \l_@@_yb_fp } \fp_set:Nn \l_@@_delta_fp { ( \l_@@_u_fp + \l_@@_v_fp )^2 + 4 * \l_@@_xa_fp * ( \l_@@_t_fp - \l_@@_yb_fp ) * ( \l_@@_xm_fp * ( \l_@@_yb_fp - \l_@@_ym_fp ) - \l_@@_xb_fp * \l_@@_ym_fp ) } \fp_compare:nNnTF \l_@@_delta_fp < \c_zero_fp { \fp_set_eq:NN \l_@@_sqrt_fp \c_nan_fp } { \fp_set:Nn \l_@@_sqrt_fp { sqrt(\l_@@_delta_fp) } } } \cs_new_eq:NN \diagbox@solve@equations \@@_solve_equations: \fp_new:N \l_@@_xa_fp \fp_new:N \l_@@_ya_fp \fp_new:N \l_@@_xb_fp \fp_new:N \l_@@_yb_fp \fp_new:N \l_@@_xm_fp \fp_new:N \l_@@_ym_fp \fp_new:N \l_@@_x_fp \fp_new:N \l_@@_y_fp \fp_new:N \l_@@_s_fp \fp_new:N \l_@@_t_fp \fp_new:N \l_@@_u_fp \fp_new:N \l_@@_v_fp \fp_new:N \l_@@_sqrt_fp \fp_new:N \l_@@_delta_fp \msg_new:nnn { diagbox } { calculate-error } { Cannot~calculate~proper~#1~of~triple~diagbox~ \msg_line_context:. \\ Use~#2pt~instead. } \file_input_stop: % \end{macrocode} % % 若 \pkg{l3fp} 不可用,则引入 \pkg{fp} 包计算。 % \begin{macrocode} \fi \RequirePackage{fp} \FPmessagesfalse \def\diagbox@solve@equations{% % \end{macrocode} % 取长宽 % \begin{macrocode} \edef\xa{\strip@pt\wd\diagbox@boxa}% \edef\ya{\strip@pt\dimexpr\ht\diagbox@boxa+\dp\diagbox@boxa\relax}% \edef\xb{\strip@pt\wd\diagbox@boxb}% \edef\yb{\strip@pt\dimexpr\ht\diagbox@boxb+\dp\diagbox@boxb\relax}% \edef\xm{\strip@pt\wd\diagbox@boxm}% \edef\ym{\strip@pt\dimexpr\ht\diagbox@boxm+\dp\diagbox@boxm\relax}% % \end{macrocode} % 列方程,计算方程系数 % \begin{macrocode} \FPneg\bi\yb \FPadd\ci\xb\xm \FPneg\ci\ci \FPmul\di\xm\yb \FPadd\bj\ya\ym \FPneg\bj\bj \FPneg\cj\xa \FPmul\dj\xa\ym % \end{macrocode} % 检查可行解条件,解二次方程。这里对于无正实根的情形,会给出一个宽松的值作为斜 % 线盒子的宽高: % \begin{align*} % x &= 2 \max(x_a + x_m, x_b + x_m),\\ % y &= 2 \max(y_a + y_m, y_b + y_m). % \end{align*} % \begin{macrocode} \FPsub\u\dj\di \FPupn{v}{bj ci * bi cj * -}% \FPupn{delta}{bi dj * bj di * - cj ci - * 4 * v u + copy * -}% \newif\ifdeltapositive \FPifneg\delta \deltapositivefalse \else \deltapositivetrue \fi \FPset\x{0}% \FPset\y{0}% \ifdim\diagbox@wd=\z@ \ifdim\bi\p@>\bj\p@\ifdeltapositive \FPupn{x}{2 bj bi - 2 delta root v u - + / /}% \fi\fi \ifdim\x\p@=\z@ \FPupn{x}{xa xm + xb xm + max 2 *}% \PackageWarning{diagbox}{Cannot calculate proper width of triple diagbox.\MessageBreak Use \x pt instead.}% \fi \diagbox@wd=\x\p@ \else \edef\x{\strip@pt\diagbox@wd}% \fi \ifdim\diagbox@ht=\z@ \ifdim\ci\p@<\cj\p@\ifdeltapositive \FPupn{y}{2 cj ci - 2 delta root v u + - / /}% \fi\fi \ifdim\y\p@=\z@ \FPupn{y}{ya ym + yb ym + max 2 *}% \PackageWarning{diagbox}{Cannot calculate proper height of triple diagbox.\MessageBreak Use \y pt instead.}% \fi \diagbox@ht=\y\p@ \else \edef\y{\strip@pt\diagbox@ht}% \fi \FPsub\xxm\x\xm \FPsub\yym\y\ym } % \end{macrocode} % \end{macro} % % \iffalse % % \fi % % \Finale \endinput