我正在尝试创建一个宏,\fbox
通过在所有情况下都能正常工作并在填充方面尽量减少侵入性来改进。到目前为止,我得到的宏运行得相当好,但在某些情况下,我在测量文本宽度、高度和深度时遇到了麻烦。我的问题是我该如何正确计算这些?
为什么我不喜欢 \fbox:
请注意下面如何
\fbox
在 ',' 和 'l' 上使边界框正确,但是在以 调用时完全弄乱分数大小$\frac{\fbox{1}}{\fbox{2}}$
,而在以 调用时完全弄乱上标大小$x^{\fbox{2}}$
。\fbox
制定规则大约边界框而不是边界框内部。因此,无论规则有多细,它仍然会改变被框住的文本的尺寸。换句话说,\fbox
并不是微创的。下面,使用和设置填充和线条粗细\setlength\fboxsep{0pt}
。\setlength\fboxrule{0.001pt}
设置\fboxrule
为0pt
会导致规则完全消失。
首次尝试非侵入式盒子(使用 \vrule):
我第一次尝试使用\vrule
。这很好,但当边界框与另一个字符重叠时,它会遮挡文本,例如下面的“r”。更糟糕的是,我不知道如何在框周围画一条暗线。所以我放弃了这个想法。
第二次尝试(使用 TikZ):
接下来,我使用 TikZ 绘制了一个半透明的填充框。边缘不是框周围的描边路径,而是四个非常薄的填充矩形里面边界框。
现在这有点进展了。然而,问题在于我如何测量边界框的宽度、高度和深度。我使用\settowidth
、\settoheight
和\settodepth
并将值#1
传递给宏。这种方法对于常规文本非常有效,但一旦某些内容处于上标、下标、分数或堆叠关系中(或出于任何原因处于任何其他字体或大小中),它就会崩溃。
问题:
如您所见,下面某些元素的宽度、高度和深度计算有误。最令人震惊的是\cdot
,它的边界框出现在其左侧,因为我的宏不知道它是一个需要额外空间的二元关系运算符。我不确定这是否可以修复,但至少有某种方法可以修复上标和下标吗?因为虽然出现了未受干扰的间距,但它是基于(正常大小和样式)而不是(下标数学大小和样式)来测量边界框$v_{\fillbox{x}}$
的大小。x
#1
x
_x
最后,为什么堆叠关系会扰乱水平间距?
最小工作示例:
\documentclass{article}
\usepackage{tikz}
\makeatletter
\newlength\fillbox@height%
\newlength\fillbox@depth%
\newlength\fillbox@width%
\newcommand{\fillbox}[1]{%
\ifmmode%
\settoheight{\fillbox@height}{$#1$}%
\settodepth{\fillbox@depth}{$#1$}%
\settowidth{\fillbox@width}{$#1$}%
\else%
\settoheight{\fillbox@height}{#1}%
\settodepth{\fillbox@depth}{#1}%
\settowidth{\fillbox@width}{#1}%
\fi%
\raisebox{-\fillbox@depth}{%
\begin{tikzpicture}[scale=1]
\pgfsetfillcolor{yellow!90!red}
\pgfsetfillopacity{0.5}
\pgfsetrectcap
\fill (0,-\fillbox@depth) rectangle (\fillbox@width,\fillbox@height);
\pgfsetfillcolor{yellow!50!black}
\pgfsetfillopacity{1}
\fill (0,-\fillbox@depth)
rectangle (\fillbox@width,-\fillbox@depth+.1pt);
\fill (0,\fillbox@height)
rectangle (\fillbox@width,\[email protected]);
\fill (0,-\fillbox@depth)
rectangle (.1pt,\fillbox@height);
\fill (\fillbox@width,-\fillbox@depth)
rectangle (\[email protected],\fillbox@height);
\end{tikzpicture}%
\kern-\fillbox@width%
}%
#1%
}
\makeatother
\begin{document}
\vskip1em
$\fillbox{p}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{(}\fillbox{\frac{\fillbox{1}}{\fillbox{2}}}\fillbox{\cdot}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}^{\fillbox{2}}\fillbox{)} \fillbox{+}
\fillbox{(}\fillbox{v}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}\fillbox{)}$\fillbox{;}\par
$\fillbox{v}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}$\fillbox{;}\par
\vskip1em
$p_x \mathrel{\stackrel{_{~+}}{\leftarrow}}
(\frac{1}{2}\cdot a_x\cdot\Delta t^2) + (v_x\cdot\Delta t)$;\par
$v_x \mathrel{\stackrel{_{~+}}{\leftarrow}} a_x\cdot\Delta t$;\par
\end{document}
(注意:我没有标记这个问题,tikz
因为即使它使用了 TikZ,问题实际上是关于间距和装箱;恰好使用了 TikZ。)
答案1
数学模式中的任何框命令都需要在所有样式中设置,以便 TeX 稍后可以选择正确的命令;该\mathchoice
命令就是您在这里所需要的。请参阅我的反对\over
前几天在这个网站上:-)如果您只是使用,\hbox{$...$}
那么您将在下标位置以文本大小开始一个新的数学列表。
您可以使用和朋友重新确认构造周围的正确间距\mathbin
\mathop
,这可以通过查找\mathcode
您正在装箱的字符的来自动完成。检查bm.sty
可能会有所帮助,这会在将内容加粗后重新确认正确的数学类别,但问题是相似的。
现在重新创建bm
审讯有点晚了,\mathcode
所以这只是研究特殊情况\cdot
,+
但除此之外,我怀疑还是有一些合理的
更新最后,我放置了一个版本,它可以自动从字符标记中挑选出数学类,比如\cdot
由 定义的东西和带有显式\mathchar
的东西。我将保留原始版本,因为数学类检测可能会掩盖测量的逻辑,而这也许是问题的主要部分。\log
\mathop
\documentclass{article}
\usepackage{amsmath,color}
\makeatletter
\def\fb@cdot{\cdot}
\def\fb@p{+}
\def\@mfbox#1{%
\def\fb@{#1}%
\ifx\fb@\fb@cdot\mathbin\fi
\ifx\fb@\fb@p\mathbin\fi
{\text{\fboxsep\z@\colorbox{yellow}{$\m@th#1$}}}}
\def\@tfbox#1{{\fboxsep\z@\colorbox{yellow}{#1}}}
\def\fillbox#1{\ifmmode\expandafter\@mfbox\else\expandafter\@tfbox\fi{#1}}
\begin{document}
\vskip1em
$\fillbox{p}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{(}\fillbox{\frac{\fillbox{1}}{\fillbox{2}}}\fillbox{\cdot}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}^{\fillbox{2}}\fillbox{)} \fillbox{+}
\fillbox{(}\fillbox{v}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}\fillbox{)}$\fillbox{;}\par
$\fillbox{v}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}$\fillbox{;}\par
\vskip1em
$p_x \mathrel{\stackrel{_{~+}}{\leftarrow}}
(\frac{1}{2}\cdot a_x\cdot\Delta t^2) + (v_x\cdot\Delta t)$;\par
$v_x \mathrel{\stackrel{_{~+}}{\leftarrow}} a_x\cdot\Delta t$;\par
\end{document}
bm
使用-style 数学类检测的版本。
\documentclass{article}
\usepackage{amsmath,color}
\makeatletter
\def\fb@eat#1#2#3#4#5{\futurelet\fb@let@token\fb@eat@}
\def\fb@eat@#1\fb@eat{%
\ifx\fb@let@token\bgroup
\else\ifx\fb@let@token\mathop
\mathop
\else\ifx\fb@let@token\mathbin
\mathbin
\else\ifx\fb@let@token\mathrel
\mathrel
\else\ifx\fb@let@token\mathopen
\mathopen
\else\ifx\fb@let@token\mathop
\mathop
\else\ifx\fb@let@token\mathpunct
\mathpunct
\else\ifcat.\ifcat a\noexpand\fb@let@token.\else\noexpand\fb@let@token\fi
\afterassignment\fb@mathchar\count@\mathcode`#1\relax\fb@eat
\else\ifx\fb@let@token\mathchar
\afterassignment\fb@mathchar\expandafter\count@\@gobble#1\relax\fb@eat
\else
\xdef\meaning@{\meaning\fb@let@token}%
\expandafter\fb@mchar@test\meaning@""\@nil
\fi\fi\fi\fi\fi\fi\fi\fi\fi
}
\def\@mfbox#1{%
\begingroup
\let\protect\empty
\expandafter\fb@eat\romannumeral`\Q#1\relax\fb@eat
\ifcase\count@
\or
\mathop\or
\mathbin\or
\mathrel\or
\mathopen\or
\mathclose\or
\mathpunct\or
\fi
{\text{\fboxsep\z@\colorbox{yellow}{$\m@th#1$}}}%
\endgroup}
\edef\fb@mchar@{\meaning\mathchar}
\def\fb@mchar@test#1"#2"#3\@nil{%
\xdef\meaning@{#1}%
\ifx\meaning@\fb@mchar@
\count@"#2\relax
\fb@mathchar\fb@eat
\fi
}
\def\fb@mathchar#1\fb@eat{%
\divide\count@"1000 }
\def\@tfbox#1{{\fboxsep\z@\colorbox{yellow}{#1}}}
\def\fillbox#1{\ifmmode\expandafter\@mfbox\else\expandafter\@tfbox\fi{#1}}
\begin{document}
$a-b$
$a{-}b$
$a\fillbox{-}b$
$\log x + \mathrm{log}x$
$\fillbox{\log} \fillbox{x} \fillbox{+} \fillbox{\mathrm{log}}\fillbox{x}$
$\fillbox{0}$
$ a \cdot b {\cdot} c$
$ a \fillbox{\cdot} b \fillbox{{\cdot}}c $
$a \fillbox{\mathchar"2201} b \fillbox{{\mathchar"2201}} c $
$ a - b < \alpha $
$\fillbox{a} \fillbox{-} \fillbox{b} \fillbox{<} \fillbox{\alpha}$
$\fillbox{a+b}$
$a = \sqrt{h}$
$a = \fillbox{\sqrt{h}}$
\vskip1em
$\fillbox{p}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{(}\fillbox{\frac{\fillbox{1}}{\fillbox{2}}}\fillbox{\cdot}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}^{\fillbox{2}}\fillbox{)} \fillbox{+}
\fillbox{(}\fillbox{v}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}\fillbox{)}$\fillbox{;}\par
$\fillbox{v}_{\fillbox{x}}
\mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
\fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
\fillbox{\Delta}\fillbox{t}$\fillbox{;}\par
\vskip1em
$p_x \mathrel{\stackrel{_{~+}}{\leftarrow}}
(\frac{1}{2}\cdot a_x\cdot\Delta t^2) + (v_x\cdot\Delta t)$;\par
$v_x \mathrel{\stackrel{_{~+}}{\leftarrow}} a_x\cdot\Delta t$;\par
\end{document}
制作
答案2
为了回应提问者想要修复下标和上标的框问题,该scalerel
包有办法将当前的数学样式带到原本会丢失的地方。语法是,\ThisStyle{...\SavedStyle...}
它将把当前位置有效的数学样式导入到调用的\ThisStyle
位置。\SavedStyle
\documentclass{article}
\usepackage{scalerel}
\fboxsep=0pt
\newcommand\boxit[1]{\ThisStyle{\fbox{$\SavedStyle#1$}}}
\begin{document}
\[
y = x^{\boxit{2}}
\]
\end{document}