|
前几天和 86鱼 聊起这帖:tex.stackexchange.com/questions/461451/
鉴于Qiang的缘故,帖中的图片可能无法显示,只好把内容截图过来:
要实现这种效果,双层括号,还要有编号:
帖中有两个解答,前者用 zref-savepos,后者用 tikz,实现的原理应该是类似的,就是在公式后面放“锚”(或许有更合适的形容词),由此确定括号的位置和大小啥的,一般需要编译两次,位置才准确。
由于我比较喜欢玩 tikz,而且以前也定义过类似的命令(kuing.cjhb.site/forum.php?mod=viewthread&tid=5069),所以我主要看后者的代码:- \documentclass{article}
- \usepackage{amsmath,tikz}
- \begin{document}
- \newcommand{\tkzmark}[1]{\tikz[remember picture, overlay]{\coordinate(#1);}}
- \begin{align}
- eq1\tkzmark{0} \\
- eq2\tkzmark{1} \\
- eq3 \\
- eq4
- \end{align}
- \begin{tikzpicture}[remember picture, overlay]
- \node at ([shift={(.5em,-.5em)}]0)[right] {$\left.\rule{0pt}{1.2\baselineskip}\right\} \forall i \in N$};
- \node at ([shift={(5em,-.5em)}]1)[right] {$\left.\rule{0pt}{2.5\baselineskip}\right\} \forall t \in N$};
- \end{tikzpicture}
- \end{document}
复制代码
表面看起来没问题,但细看发现写得不咋样,主要是这两处:- \left.\rule{0pt}{1.2\baselineskip}\right\}
- \left.\rule{0pt}{2.5\baselineskip}\right\}
复制代码 括号大小竟然是手工输入若干倍行距来调的,问题是这 1.2 和 2.5 是如何确定的?或许当公式都是一般高度时的确可以直接知道,但如果有较高的公式,就不好知道了吧?恐怕得调试几次,这就不科学了。
正常的操作当然是利用锚点来计算,比如我当时给 86鱼 发的酱紫:- \documentclass{article}
- \usepackage{amsmath}
- \usepackage{tikz}
- \usetikzlibrary{calc}
- \newcommand\tikzmark[2][0,0]{%
- \tikz[baseline,remember picture,overlay]
- \coordinate (#2) at (#1);}
- \newcommand\vct[1]{\vcenter{\hbox{#1}}}
- \begin{document}
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \begin{align}
- f(x) &= {ax^2 + bx + c}^{\tikzmark A} \\
- ax^2 + bx + c &= g(x)_{\tikzmark B} \\
- h(x) &= dx^3 + ex^2 + fx + h \\
- dx^3 + ex^2 + fx + h &= i(x)_{\tikzmark D}
- \end{align}
- \tikz[remember picture,overlay]{
- \node[right] at ($(A)!0.5!(A|-B)$)
- {$\left.\vct{\tikz\path(A)(A|-B);}\right\}\forall i \in N$};
- \node[right=1.4cm] at ($(A)!0.5!(A|-D)$)
- {$\left.\vct{\tikz\path(A)(A|-D);}\right\}\forall t \in N$};
- }%
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \end{document}
复制代码 效果:
改进之处除了括号大小的问题,还有锚的位置,为了让锚点位于公式的顶部,我用了 ^{\tikzmark A}(其实这也不是最准确)。
但水平位置还是有不科学的地方,就是那个 [right=1.4cm],为了让最右边的括号不与 i∈N 重叠而右移的,这是需要调试的。还有 node 的位置是 (A)!0.5!(A|-B) 还是 (A-|B)!0.5!(B) 也要视哪条公式更长而定。
所以还可以继续改进:- \documentclass{article}
- \usepackage{amsmath}
- \usepackage{tikz}
- \usetikzlibrary{calc,fit,matrix}
- \newcommand\tikzmark[2][0,0]{%
- \tikz[baseline,remember picture,overlay]
- \coordinate (#2) at (#1);}
- \newsavebox\tmpbox
- \newcommand\tikzmarkht[2]{%
- \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,\ht\tmpbox]{#2}}
- \newcommand\tikzmarkdp[2]{%
- \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,-\dp\tmpbox]{#2}}
- \begin{document}
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \begin{align}
- \sum_{i=1}^n f(x) &= ax^2 + bx + c \tikzmarkht{\sum^n}A \\
- ax^2 + bx + c &= g(x) \tikzmarkdp(B \\
- h(x) &= dx^3 + ex^2 + fx + h \tikzmark C \\
- dx^3 + ex^2 + fx + \frac12 &= i(x) \tikzmarkdp{\frac12}D
- \end{align}
- \tikz[remember picture,overlay,
- label distance=10pt,inner sep=0pt]{
- \node[fit=(A)(B),
- label={0:$\forall i\in N$\tikzmark E},
- right delimiter=\rbrace]{};
- \node[fit=(A)(E)(C)(D),
- label={0:$\forall t\in N$},
- right delimiter=\rbrace]{};
- }%
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \end{document}
复制代码 效果:
这回为了精确地定位锚点,新定义了 \tikzmarkht 和 \tikzmarkdp ,用公式中最高或最低的东西来定点,像上图的第一条公式,就得用 \sum^n 来确定点 A。
改用 fit 来解决最右的位置,这样就不用看哪条公式长了,用 right delimiter 加括号(为此需添加 fit 和 matrix 库)。
在第一个括号的 label 的最后再加一个 tikzmark,用来确定第二个括号的位置,这样就无需调试水平距离了。
但是,由于需要第一个括号画好后才会知道 E 点的位置,所以以上代码在首次编译时需要编译三次才能画好,如果再多一层,就要再编译多一次(硬伤……),比如下面的,要编译四次 :- \documentclass{article}
- \usepackage{amsmath}
- \usepackage{tikz}
- \usetikzlibrary{calc,fit,matrix}
- \newcommand\tikzmark[2][0,0]{%
- \tikz[baseline,remember picture,overlay]
- \coordinate (#2) at (#1);}
- \newsavebox\tmpbox
- \newcommand\tikzmarkht[2]{%
- \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,\ht\tmpbox]{#2}}
- \newcommand\tikzmarkdp[2]{%
- \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,-\dp\tmpbox]{#2}}
- \begin{document}
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \begin{align}
- \sum_{i=1}^n f(x) &= ax^2 + bx + c \tikzmarkht{\sum^n}A \\
- ax^2 + bx + c &= g(x) \tikzmarkdp(B \\
- h(x) &= dx^3 + ex^2 + fx + h \tikzmarkdp)C\\
- dx^3 + ex^2 + fx + \frac12 &= i(x) \tikzmarkdp{\frac12}D
- \end{align}
- \tikz[remember picture,overlay,
- label distance=10pt,inner sep=0pt]{
- \node[fit=(A)(B),
- label={0:$XXX$\tikzmark E},
- right delimiter=\rbrace]{};
- \node[fit=(A)(E)(C),
- label={0:$YYY$\tikzmark F},
- right delimiter=\rbrace]{};
- \node[fit=(A)(F)(D),
- label={0:$ZZZ$},
- right delimiter=\rbrace]{};
- \foreach \i in {A,B,C,D,E,F} {
- \fill[red] (\i) circle (1pt);
- \draw[red,{[sep=2pt]<}-] (\i)--+(30:0.5)node[right]{(\i)};
- }
- }%
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
- \end{document}
复制代码 效果:
为了便于理解,我标注了各个锚点的位置。
但又有问题了,由于通过这种方式添加的东西是不占任何空间的,所以整个公式不会自动向左移,导致和右边的编号重叠了,还是得手工移……😭
哦还有,添加括号的语句得确保和公式在同一页,因此,如果公式刚好排到页底,括号有可能加到下一页,因此其实应该把它放到 align 里面写比较安全,不过懒得改了…… |
|