背景

背景

假设我需要创建一个新符号用作数学运算符(或关系),例如\vartriangleright带有\circ内部的:

\documentclass{article}
\usepackage{amsmath, amssymb}
\newcommand{\mysymb}{}
\begin{document}
\noindent Without the little space at the end:
\[
a \mathbin{\vartriangleright\mspace{-18.5mu}\circ} b
\]
With the little space at the end:
\[
a \mathbin{\vartriangleright\mspace{-18.5mu}\circ\mspace{3.5mu}} b
\]
\end{document}

在此处输入图片描述

由于我必须使用负字距调整来将 放在\circ上方\vartriangleright,因此我必须在末尾添加一点空格来补偿它。

我怎样才能准确计算这个小空间,而无需通过反复试验来解决它并确定我已经做了正确的补偿?

换句话说,我如何找到符号的长度\vartriangleright(或我正在使用的任何东西)以添加所需的空间?

PS = 这个问题来自一个 egreg 对我的这个答案,他已经在聊天中向我解释了,但我认为这对每个人都有用。

答案1

我正在写这篇文章(长的!) 回答,因为我向 CarLaTeX 承诺过我会这样做。我很抱歉拖延了这么久,但直到现在我才有时间完成它。

有几种方法可以找出给定字符的宽度、高度和深度,其中最简单的方法是分别使用命令\settowidth\settoheight\settodepth,这些命令由 LaTeX2e 内核定义,并在各种来源中描述,从 Lamport 的LaTeX – 文档准备系统(见第 216 页)对问题的答案检索字符的长度,已引用于一条评论对于当前的问题(但也请参阅获取给定文本的宽度作为长度;存在其他重复项)。另一种可行的方法是,如果您知道绘制相关字符的字体,则在该字体的 TFM(TeX 字体度量)文件中查找所需信息,然后将其转换为其文本表示形式,即 PL(属性​​列表)文件。

然而,这个问题并不是上述问题的完全重复,因为它涉及数学,并要求用数学单位表示所需的长度(在本例中为宽度)。我认为这里需要简短地离题一下,以便提供一些背景信息。之后,我们不仅能够更好地理解上面提到的方法,还可以问自己一个基本问题:“用数学单位测量字符宽度的能力有任何实用性吗?”——不幸的是,答案很可能是“否”。

背景

TeX 的大部分测量单位是绝对,因为它们对应于固定的物理维度(例如,1 点 = 1/72.27 英寸 = 大约 0.351460 毫米);但另一方面,有些相对的,因为它们是根据与某种字体相关的另一个维度来指定的。后一种类型的单位的更广为人知的例子可能是em和 ex,但数学单位(mu)也属于这种类型。更准确地说(参见 TeXbook,第 168 页),1mu= 的 1/18 1em,其中 的度量值 1em取自用于symbols数学组的字体(按照 NFSS 的说法;它相当于 TeX 的“系列 2”),在 LaTeX2e 内核设置的配置中,它对应于和cmsy10中的,对应于中的,以及中的;请注意,分配给 的基本度量值 会随着当前数学样式而变化,这正是数学单位也会随着当前样式而变化的原因和方式。\displaystyle\textstylecmsy7\scriptstylecmsy5\scriptscriptstyle1em

但应牢记以下几点:

  1. 由于数学单位的有效宽度取决于与symbols字体相关的参数,并且由于用于此目的的实际外部字体可能会(并且通常会)因选择不同的数学字体而变化,因此,即使符号本身在字体的新数学设置中保持不变,符号的宽度(以数学单位表示时)也可能发生变化。例如,我们将在下面介绍一种情况,在加载包后newtxmath,我们使用一种策略确保所使用的符号\vartriangleright根本不会改变(不仅它总是从msam字体系列中的同一位置获取,通常即使没有任何特殊的权宜之计也是如此,它还保持与未加载包时完全相同的大小 newtxmath),但尽管如此,它在脚本和脚本样式中以数学单位测量的宽度还是会有所不同,这正是由于数学单位的长度不同。

  2. 即使您不更改内核的数学字体设置,尽管如我们刚才所说,数学单位会根据当前数学样式进行缩放,但也不能保证符号的宽度保持不变,以数学单位衡量时,比如从 到 ;\textstyle事实上\scripstyle,我们将在下面看到,它通常会发生变化,即使对于来自与数学单位本身相同的字体系列(cmsy例如系列)的符号也是如此。

这两点说明,对于出现该问题的情况,每个依赖于代码中以文字、预先计算的值指定的字距调整量的解决方案实际上注定迟早会失败,尽管可以借助 来避免 2 中描述的问题\mathchoice

在数学中使用\settowidth(和)\widthof

我们不会详细讨论 、 和 命令的一般用法\settowidth\settoheight也不会讨论软件包提供的\settodepth配套命令\widthof\heightof\depthof\totalheightof和的用法:如前所述,有很多关于它们用法的信息来源。不过,也许值得一提的是,当您想要测量\settototalheightcalc宽度数学符号,您不应该忘记在本地重置该\mathsurround参数。回想一下,可以指示 TeX 在每个数学公式之前和之后插入一定量的字距调整:这恰恰发生在\mathsurround公式末尾的值不为零时,在这种情况下,它会给出应该应用于该特定公式的字距调整量。在 LaTeX 中,\mathsurround通常等于零,但情况并非总是如此(事实上,这个参数的存在正是因为某些出版商的内部风格要求数学公式用这种额外的字距进行排版)。因此,不要只写

\settowidth{\mylength}{$\vartriangleright$}

写出来更好,也更安全

\settowidth{\mylength}{$\mathsurround=0pt \vartriangleright$}

相反,以免您在测量中包含额外的字距调整。对的更改\mathsurround仅限于所暗示的组$...$\settowidth实际上在其周围提供了另一个组),因此它不会破坏文档其余部分中为此样式参数设置的值。

\m@th纯 TeX 和 LaTeX 都定义了的缩写\mathsurround=0pt ,因此你实际上可以写

\settowidth{\mylength}{$\m@th\vartriangleright$}

@ 当然,前提是你在字符被解释为字母的上下文中执行该语句(例如, 之间\makeatletter\makeatother

正如上述问题的答案获取给定文本的宽度作为长度解释一下将某些内容排版到临时框中,然后通过原语询问该框的宽度的技巧\wd,如下所示@CarLaTeX 的回答,正是\settowidth命令内部所做的事情;因此,上述评论\mathsurround也适用于这种技术:你应该说

\sbox0{$\mathsurround=0pt \vartriangleright$}\showthe\wd0

(或者

\sbox0{$\m@th\vartriangleright$}\showthe\wd0

如果适用的话)以防止出现不寻常的(IE,非空)设置此参数。

让 TeX 测量你的符号

有了上述的预防措施\mathsurround,就可以编写一个小程序来测量并报告给定符号的宽度(以数学单位表示);我们将使用这种程序来证明我们上面提出的主张。关于我们将要介绍的代码,应该注意以下几点:

  1. 所命名的命令\WidthInMathUnitsOf只能在 TeX 排版文本的上下文中使用,而不能在所谓的“纯可扩展上下文”中使用;这意味着,除其他事项外,它不能在某些命令的参数中使用,特别是在的参数中使用\typeout(即使您\protect使用它)。

  2. 因此,您可以使用类似的命令\WidthInMathUnitsOf在排版文本中直接打印报告测量的宽度,但不能在终端上报告。

  3. 另一方面,如果您的目的不仅仅是报告宽度,而是想要在代码中直接使用测量值来实现某些目的(例如,想要将其作为参数传递给命令\mspace),那么最好的策略是使用像我们的这样的声明\SetToWidthInMathUnits,将结果存储在控制序列中,以十进制数字字符串的形式,随后可以通过纯扩展从中检索它(您必须添加测量单位,即mu)。

  4. \WidthInMathUnitsOf和都\SetToWidthInMathUnits使用 e-TeX 的扩展计算其结果\dimexpr:这是不是\multiply与使用原始 TeX 的原语和相同\divide,因为 e-TeX 将中间结果存储为 64 位值,而使用原始 TeX,您几乎肯定会收到“算术溢出”错误(除非您玩一些技巧,但会严重影响结果的精度)。

以下是代码(必须用 进行编译pdflatex):

% My standard header for TeX.SX answers:
\documentclass[a4paper]{article} % To avoid confusion, let us explicitly 
                                 % declare the paper format.

\usepackage[T1]{fontenc}         % Not always necessary, but recommended.
% End of standard header.  What follows pertains to the problem at hand.

% \usepackage{newtxtext,newtxmath}
\usepackage{amsmath}
\usepackage{amssymb}

% % Uncomment the following line of code to undo (but only for "\normalsize", 
% % which in this document means 10 points) the change made to the math sizes by 
% % the "newtxmath" package:
% \DeclareMathSizes{10}{10}{7}{5} 

\makeatletter

\def\do#1{\@ifdefinable#1{\newdimen#1}}
\do\@TempWidthOne
\do\@TempWidthTwo
\newcommand*\WidthInMathUnitsOf[2]{%
    \settowidth\@TempWidthOne{$\m@th #1#2$}%
    \settowidth\@TempWidthTwo{$\m@th #1\mspace{1mu}$}%
    \strip@pt \dimexpr \@TempWidthOne*\p@/\@TempWidthTwo \relax
}
\newcommand*\SetToWidthInMathUnits[3]{%
    \settowidth\@TempWidthOne{$\m@th #2#3$}%
    \settowidth\@TempWidthTwo{$\m@th #2\mspace{1mu}$}%
    \edef #1{%
        \strip@pt \dimexpr \@TempWidthOne*\p@/\@TempWidthTwo \relax
    }%
}
\newcommand*\ExtractHexDigitOfFamilyOfSymbol[1]{%
    \expandafter\@ExtractHexDigitOfFamily \meaning #1% must be a cs token
}
\@ifdefinable\@ExtractHexDigitOfFamily{
    \def\@ExtractHexDigitOfFamily#1"#2#3#4#5{#3}
}

\makeatother

\newcommand*{\ReportWidthsOf}[1]{%
    \par
    \begingroup
        \setlength{\abovedisplayskip}{\smallskipamount}%
        \indent
        Width of $#1$
        (\texttt{\string #1}, \emph{i.e.}, \texttt{\meaning #1})
        in:%
        \begin{align*}%
            % \ReportWidthFor\displaystyle     {#1}\\%
            \ReportWidthFor\textstyle        {#1}\\%
            \ReportWidthFor\scriptstyle      {#1}\\%
            \ReportWidthFor\scriptscriptstyle{#1}%
        \end{align*}%
    \endgroup
}
\newcommand*{\ReportWidthFor}[2]{%
    \texttt{\string #1}&=
        \texttt{\WidthInMathUnitsOf #1{#2}mu}%
}
\newcommand*{\ReportValueOfOneEm}[1]{%
    &\text{in #1 size,}%
        &\quad\texttt{1em}%
            &=\texttt{\the \fontdimen 6 \csname #1font\endcsname 2}%
        &&\qquad\text{(from \texttt{\fontname \csname #1font\endcsname 2})}%
}
\newcommand*{\ReportSizeOfFontOfSymbol}[2]{%
    &\texttt{\pdffontsize\csname #2font\endcsname
                "\ExtractHexDigitOfFamilyOfSymbol{#1}}%
        &&\quad\text{in #2 size}%
        &\qquad(\texttt{\string\fontname}%
            &=\texttt{\fontname\csname #2font\endcsname
                "\ExtractHexDigitOfFamilyOfSymbol{#1}})%
}
\newcommand*{\ReportSizeOfMSAMFont}{%
    \ReportSizeOfFontOfSymbol{\vartriangleright}%
}

\newcommand*{\mytemp}{} % just declare the name



\begin{document}

% \show\defaultscriptratio

\ReportWidthsOf{\oplus}
\ReportWidthsOf{\wedge}
\ReportWidthsOf{\vartriangleright}

Note that \verb|\vartriangleright| now means \texttt{\meaning\vartriangleright},
but that the external font which corresponds to
family~\texttt{"\ExtractHexDigitOfFamilyOfSymbol{\vartriangleright}} remains
\texttt{\fontname\textfont"\ExtractHexDigitOfFamilyOfSymbol{\vartriangleright}}
(in text size).  On the other hand, the external font linked to the
\texttt{symbols} font family is currently \texttt{\fontname\textfont2} (again in
text size), in which \( \texttt{1em} = \texttt{\the \fontdimen6 \textfont2} \).
More generally, for this \texttt{symbols} font family it turns out that:
%
\begin{alignat*}{3}
    \ReportValueOfOneEm{text};\\
    \ReportValueOfOneEm{script};\\
    \ReportValueOfOneEm{scriptscript}.
\end{alignat*}
%
But---surprise!\@---the packages that configure the math fonts sometimes
redeclare the math sizes for the script and scriptscript styles (for example,
the \texttt{newtxmath} package does so), and this affects also the sizes at
which the fonts of the \texttt{msam} family are loaded.  Indeed, in the present
run those fonts are loaded at the following sizes:
%
\begin{alignat*}{3}
    \ReportSizeOfMSAMFont{text};\\
    \ReportSizeOfMSAMFont{script};\\
    \ReportSizeOfMSAMFont{scriptscript}.
\end{alignat*}
%

% Use the computed width in the argument of another command:

\SetToWidthInMathUnits{\mytemp}{\textstyle}{\vartriangleright}

% \show\mytemp

Now \verb|\mytemp| is \texttt{\mytemp}, and can be used in the argument of
another command:\\
X[$\vartriangleright$]X\\
X[$\mspace{\mytemp mu}$]X

\end{document}

如果您按原样编译此代码,将使用 Computer Modern 字体,并且您将获得以下输出:

使用 CM 字体输出

另一方面,如果你取消注释以下行:

% \usepackage{newtxtext,newtxmath}

将改用“newtx”字体,输出将是

使用 newtx 字体输出

我们看到,虽然 的符号\vartriangleright始终取自同一来源(即 字体系列”42的插槽msam),但在脚本大小中,其宽度(以数学单位表示)与以前有显著不同。然而,这在一定程度上是一个错误的线索,因为该newtxmath包略微改变了主符号使用的数学大小与脚本和双脚本使用的数学大小之间的比率,这也影响了msam7msam5字体的加载大小,如输出所示。因此,您有第三个选择:如果您(在启用“newtx”字体(如我们刚才所做的那样)后取消注释以下代码行

% \DeclareMathSizes{10}{10}{7}{5} 

包对数学大小应用的更改newtxmath被撤消(但仅限于在 中排版的公式\normalsize)。在这种情况下,输出如下所示:

使用 7pt 和 5pt 的 newtx 字体输出

请注意,即使在这种情况下,ntxsy7字体也会以 加载at 7.0pt,也就是说,不是以其标称设计大小(如下文所示,为 10pt),类似的注释ntxsy5也适用于 。另一方面,msam7msam5字体以其设计大小(分别为 7pt 和 5pt)加载,与我们的第一个实验完全一样;这毫无疑问证明了 宽度的差异\vartriangleright(Computer Modern 实验:13.72888mu\scriptstyle13.24544mu\scriptscriptstyle;本实验: 16.07161mu\scriptstyle19.50072mu\scriptscriptstyle)纯粹是由于,至少在这种情况下,数学单位的缩小。

在 TFM 文件中查找测量值

您也可以不要求 TeX 找出它,而是直接在包含相关字符的字体的 TFM(TeX 字体度量)文件中查找所需的度量;当然,我们在此假设此字体是“经典”TeX 字体,因为如果您使用的是“经典”引擎(TeX 或 pdfTeX),情况总是如此。但请记住,在 TFM 文件中,所有与字符相关的尺寸都以相对单位表示,一个相对单位等于atTeX 加载字体的大小;默认情况下,TeX 会以其设计大小加载每个字体,这也在字体的 TFM 文件中指定。为了展示如何在以设计大小加载字体和以自定义大小(用子句指定)加载字体的情况下处理从这些相对单位到绝对单位的转换,我们选择举例说明在使用“newtx”字体时at以数学单位测量字符宽度的过程,\vartriangleright\scriptstyle在我们的“数学尺寸恢复”策略生效的情况下(参见上面的第三个实验):这将涉及以其设计尺寸()加载的字体和即加载的msam7字体,后者是提供一个数学单位宽度的字体。ntxsy7at 7.0pt

您需要做的第一件事是将相关的 TFM 文件转换为人类可读的对应文件,即 PL(属性​​列表)文件;这很像将目标代码文件反汇编为人类可读的文本文件。因此,转到您选择的干净目录并在 shell 提示符下键入以下内容:

tftopl msam7.tfm msam7.pl
tftopl ntxsy7.tfm ntxsy7.pl

tftopl实用程序应自动从您的 TEXMF 树中选择.tfm文件,并将相应的.pl文件保存在本地目录中。

接下来,msam7.pl在任何文本编辑器中打开该文件;它的第一行应该是

(FAMILY MSAM V2.2)
(FACE O 360)
(CODINGSCHEME TEX MATH SYMBOLS)
(DESIGNSIZE R 7.0)
(COMMENT DESIGNSIZE IS IN POINTS)
(COMMENT OTHER SIZES ARE MULTIPLES OF DESIGNSIZE)
(CHECKSUM O 27035367067)

上面写着

(DESIGNSIZE R 7.0)

告诉(正如您所预料的!)此字体的设计大小为 7.0pt;在我们上面发布的代码中,这也是此字体加载时的大小。因此,文件中显示的所有后续大小都msam7.pl必须乘以 7.0pt,才能找到它们的实际绝对值。现在,在文件中向下滚动,msam7.pl直到找到以下行

(CHARACTER O 102
   (CHARWD R 0.892861)
   (CHARHT R 0.565615)
   (CHARDP R 0.075675)
   )

102这是以八进制 ( ) 表示法表示的字符的描述 ,八进制表示法与十六进制表示O法相同;因此,它正是与 相对应的字符,正如我们上面所见。其宽度由关键字后面的实数 ( ) 给出;将此数字 ( ) 乘以 7.0pt,我们得到绝对宽度 6.250027pt。42\vartrianglerightRCHARWD0.892861

现在我们必须找出 中一个数学单位的宽度\scriptstyle:这是字体中 1em 宽度的 1/18 ntxsy7。因此,我们打开ntxsy7.pl,发现它是这样开始的:

(FAMILY UNSPECIFIED)
(FACE F MRR)
(CODINGSCHEME TEX MATH SYMBOLS)
(DESIGNSIZE R 10.0)
(COMMENT DESIGNSIZE IS IN POINTS)
(COMMENT OTHER SIZES ARE MULTIPLES OF DESIGNSIZE)
(CHECKSUM O 31601054554)
(SEVENBITSAFEFLAG TRUE)
(FONTDIMEN
   (SLANT R 0.0)
   (SPACE R 0.0)
   (STRETCH R 0.0)
   (SHRINK R 0.0)
   (XHEIGHT R 0.441)
   (QUAD R 1.0)
   (EXTRASPACE R 0.0)
   (NUM1 R 0.677)
   (NUM2 R 0.394)
   (NUM3 R 0.444)
   (DENOM1 R 0.686)
   (DENOM2 R 0.345)
   (SUP1 R 0.413)
   (SUP2 R 0.363)
   (SUP3 R 0.289)
   (SUB1 R 0.15)
   (SUB2 R 0.247)
   (SUPDROP R 0.386)
   (SUBDROP R 0.05)
   (DELIM1 R 2.39)
   (DELIM2 R 1.01)
   (AXISHEIGHT R 0.257)
   )

我们从上面的实验中了解到,此字体已加载at 7.0pt不是设计尺寸为 10.0pt(根据该DESIGNSIZE行,即使这应该是——或者更好地说,应该是用过的即“7 点”字体)。因此,文件其余部分给出的相对尺寸应乘以的量再次为 7.0pt,尽管原因与之前不同。要获得 1em 的测量值,我们必须查看列表QUAD中的项目FONTDIMEN:我们读取

   (QUAD R 1.0)

因此我们得到 1em = 1.0 × 7.0pt = 7.0pt(正如我们实验的输出所示);然后,1mu = 7.0pt/18 = 0.388889pt。

最后,将 6.250027pt 除以 0.388889pt,我们发现的宽度\vartriangleright(以数学单位表示)为 16.07149。在我们的实验中,16.07161mu报告的宽度为:差异 0.00012mu 大约相当于 0.00005pt,或约 3sp,因此完全可以通过舍入误差来解释。

此外,需要注意的是,在这种情况下,两种字体都以相同的大小加载,将大小转换为绝对单位的步骤(在我们的示例中,将它们乘以 7.0pt)显然是多余的。

如果你有兴趣了解如何读取和写入 PL 文件,请输入

texdoc pltotf

在命令行提示符下阅读所提交文档的第 7-14 节(5 页)。

结论

我希望上述讨论已经详尽地表明,为了构建复合符号,通过在代码中指定合适的退格键(以数学单位给出的文字、预计算量)来叠印两个符号的方法远远不够强大,无法部署在任何通用应用程序中,最多只能被视为临时解决方案。使用数学单位的背后思想可能是相信以这些单位指定的数量会在脚本和脚本样式中自动缩小,但我们已经看到事实并非如此。原则上,可以将文字预计算量替换为运行时计算的量,同时考虑当前的数学字体配置;但这种解决方案无法与该\ooalign方法进行比较,因为:

  • 它将需要在 TeX 解释器级别复制或多或少与所调用的\halign原语\ooalign在主机的机器代码级别执行的计算相同的计算;

  • 它会不是避免诉诸\mathchoice(该 \ooalign方法要求采取适当的措施才能正确行事)。

综上所述\ooalign解决此类问题的方法。

答案2

由于 egreg 不想免费获得 15 分 (@yo'),所以我将尝试自己回答。

当然,符号的宽度取决于您使用的字体。

要找到实际宽度(以点为单位),您可以使用\sbox0{$<your_symbol>$}(添加\showthe\wd0到日志文件中打印),然后将其除以 1 个数学单位的宽度(以点为单位)\sbox0{$\mspace{1mu}$}

通过这种方式,您可以找到符号的数学单位宽度,并可以轻松计算出要应用的正确字距。

\sbox就像\savebox没有可选参数一样,例如,这里与其一起使用\wd

在示例中,\sbox0{$\vartriangleright$}\showthe\wd0您将在日志文件中读到 7.7778pt。

\sbox0{$\mspace{1mu}$}\showthe\wd0日志中你会读到 0.55554pt。

\sbox0{$\circ$}\showthe\wd0日志中你会读到 5.00002pt。

因此,以数学单位表示的宽度$\vartriangleright$为 7.7778/0.55554=14,并且,由于您需要 -18.5 个数学单位来补偿(并且$\circ$更短,9 个数学单位),所以正确的字距调整为 18.5-14=4.5。

\stackengine通过这种方式,就可以找到与或等价的解\ooalign

有关\stackengine宏的更多信息,请参阅文档华丽的 Steven 软件包,第 2.3.1 小节。

关于的一些详细解释\ooalign可以在这里找到 - 一如既往的好 -egreg 的回答

在下面的代码中,我添加了一些\vlines 来更清楚地显示对齐。

编辑:

正如 Gustavo 指出的那样,从到或 到 的解\mspace并不保持不变。首先,需要在 周围,否则,新符号在该段落中会混乱。但是,会变得错位:\textstyle\scriptstyle\scriptscriptstyle{..}\vartriangleright\circ

\documentclass{article}
\usepackage{amsmath, amssymb, stackengine}
\newcommand{\stsym}{\mathbin{\ensurestackMath{%
            \stackengine{0pt}{\vartriangleright}{\circ\mkern3.5mu}{O}{c}{F}{T}{L}}}}
\newcommand{\oosym}{\mathbin{\ooalign{$\vartriangleright$\cr$\mkern.5mu\circ$\cr}}}
\newcommand{\mssym}{\mathbin{{\vartriangleright}\mspace{-13.5mu}\circ\mspace{4.5mu}}}

\begin{document}
\begin{tabular}{ll}
Only \textbackslash\texttt{vartriangleright} for bechmark: 
&
$a\vline\mathbin{\vartriangleright}\vline b$ 
\\
Steven's solution (with \textbackslash\texttt{stackengine}): 
&
$a\vline\stsym\vline b$ 
\\
Solution with \textbackslash\texttt{ooalign}: 
&
$a\vline\oosym\vline b$ 
\\
Solution with \textbackslash\texttt{mspace} and the correct kerning: 
&
$a\vline\mssym\vline b$ 
\\
Original example of the question: 
&
$a\vline\mathbin{\vartriangleright\mspace{-18.5mu}\circ\mspace{3.5mu}}\vline b$ 
\\
\end{tabular}
\vspace{10pt}

\begin{tabular}{ll}
Example in \textbackslash\texttt{scriptstyle}:& \\  
Only \textbackslash\texttt{vartriangleright} for bechmark: 
&
$x_{a\vline\mathbin{\vartriangleright}\vline b}$ 
\\
Steven's solution (with \textbackslash\texttt{stackengine}): 
&
$x_{a\vline\stsym\vline b}$ 
\\
Solution with \textbackslash\texttt{ooalign}: 
&
$x_{a\vline\oosym\vline b}$ 
\\
Solution with \textbackslash\texttt{mspace} and the correct kerning: 
&
$x_{a\vline\mssym\vline b}$ 
\\
Original example of the question: 
&
$x_{a\vline\mathbin{\vartriangleright\mspace{-18.5mu}\circ\mspace{3.5mu}}\vline b}$ 
\\
\end{tabular}

\sbox0{$\vartriangleright$}\showthe\wd0
\sbox0{$\mspace{1mu}$}\showthe\wd0
\sbox0{$\circ$}\showthe\wd0
\end{document}

输出:

在此处输入图片描述

日志消息:

> 7.7778pt.
l.30 \sbox0{$\vartriangleright$}\showthe\wd0


> 0.55554pt.
l.31 \sbox0{$\mspace{1mu}$}\showthe\wd0


> 5.00002pt.
l.32 \sbox0{$\circ$}\showthe\wd0

答案3

这种stackengine方法并不能消除手动计算移位的需要(因为如果不进行检查就无法知道字形的边距)。

但是,这种方法确实简化了事情,因为堆叠的项目(在本例中是移位的\circ)不会影响的底层数学间距\mathbin{\vartriangleleft}。这种效果是因为调用\useanchorwidth的参数 7\stackengine设置为True 而产生的。

\documentclass{article}
\usepackage{amsmath, amssymb,stackengine}
\newcommand\mysym{\mathbin{\ensurestackMath{%
  \stackengine{0pt}{\vartriangleright}{\circ\mkern3.5mu}{O}{c}{F}{T}{L}}}}
\begin{document}
\[
a \mysym b
\]
\end{document}

在此处输入图片描述

相关内容