找回密码
 快速注册
搜索
查看: 1008|回复: 0

再扯 tikzmark

[复制链接]

730

主题

1万

回帖

9万

积分

积分
93613
QQ

显示全部楼层

kuing 发表于 2020-3-8 21:31 |阅读模式
前几天和 86鱼 聊起这帖:tex.stackexchange.com/questions/461451/
鉴于Qiang的缘故,帖中的图片可能无法显示,只好把内容截图过来:
要实现这种效果,双层括号,还要有编号:
QQ截图20200308171423.jpg
帖中有两个解答,前者用 zref-savepos,后者用 tikz,实现的原理应该是类似的,就是在公式后面放“锚”(或许有更合适的形容词),由此确定括号的位置和大小啥的,一般需要编译两次,位置才准确。
由于我比较喜欢玩 tikz,而且以前也定义过类似的命令(kuing.cjhb.site/forum.php?mod=viewthread&tid=5069),所以我主要看后者的代码:
  1. \documentclass{article}
  2. \usepackage{amsmath,tikz}
  3. \begin{document}
  4. \newcommand{\tkzmark}[1]{\tikz[remember picture, overlay]{\coordinate(#1);}}
  5. \begin{align}
  6. eq1\tkzmark{0} \\
  7. eq2\tkzmark{1}  \\
  8. eq3 \\
  9. eq4
  10. \end{align}
  11. \begin{tikzpicture}[remember picture, overlay]
  12. \node at ([shift={(.5em,-.5em)}]0)[right] {$\left.\rule{0pt}{1.2\baselineskip}\right\} \forall i \in N$};
  13. \node at ([shift={(5em,-.5em)}]1)[right] {$\left.\rule{0pt}{2.5\baselineskip}\right\} \forall t \in N$};
  14. \end{tikzpicture}
  15. \end{document}
复制代码
QQ截图20200308214130.png
表面看起来没问题,但细看发现写得不咋样,主要是这两处:
  1. \left.\rule{0pt}{1.2\baselineskip}\right\}
  2. \left.\rule{0pt}{2.5\baselineskip}\right\}
复制代码
括号大小竟然是手工输入若干倍行距来调的,问题是这 1.2 和 2.5 是如何确定的?或许当公式都是一般高度时的确可以直接知道,但如果有较高的公式,就不好知道了吧?恐怕得调试几次,这就不科学了。

正常的操作当然是利用锚点来计算,比如我当时给 86鱼 发的酱紫:
  1. \documentclass{article}
  2. \usepackage{amsmath}
  3. \usepackage{tikz}
  4. \usetikzlibrary{calc}
  5. \newcommand\tikzmark[2][0,0]{%
  6. \tikz[baseline,remember picture,overlay]
  7. \coordinate (#2) at (#1);}
  8. \newcommand\vct[1]{\vcenter{\hbox{#1}}}
  9. \begin{document}
  10. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  11. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  12. \begin{align}
  13. f(x) &= {ax^2 + bx + c}^{\tikzmark A} \\
  14. ax^2 + bx + c &= g(x)_{\tikzmark B} \\
  15. h(x) &= dx^3 + ex^2 + fx + h \\
  16. dx^3 + ex^2 + fx + h &= i(x)_{\tikzmark D}
  17. \end{align}
  18. \tikz[remember picture,overlay]{
  19. \node[right] at ($(A)!0.5!(A|-B)$)
  20. {$\left.\vct{\tikz\path(A)(A|-B);}\right\}\forall i \in N$};
  21. \node[right=1.4cm] at ($(A)!0.5!(A|-D)$)
  22. {$\left.\vct{\tikz\path(A)(A|-D);}\right\}\forall t \in N$};
  23. }%
  24. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  25. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  26. \end{document}
复制代码
效果:
QQ截图20200308205509.png
改进之处除了括号大小的问题,还有锚的位置,为了让锚点位于公式的顶部,我用了 ^{\tikzmark A}(其实这也不是最准确)。
但水平位置还是有不科学的地方,就是那个 [right=1.4cm],为了让最右边的括号不与 i∈N 重叠而右移的,这是需要调试的。还有 node 的位置是 (A)!0.5!(A|-B) 还是 (A-|B)!0.5!(B) 也要视哪条公式更长而定。

所以还可以继续改进:
  1. \documentclass{article}
  2. \usepackage{amsmath}
  3. \usepackage{tikz}
  4. \usetikzlibrary{calc,fit,matrix}
  5. \newcommand\tikzmark[2][0,0]{%
  6. \tikz[baseline,remember picture,overlay]
  7. \coordinate (#2) at (#1);}
  8. \newsavebox\tmpbox
  9. \newcommand\tikzmarkht[2]{%
  10. \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,\ht\tmpbox]{#2}}
  11. \newcommand\tikzmarkdp[2]{%
  12. \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,-\dp\tmpbox]{#2}}
  13. \begin{document}
  14. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  15. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  16. \begin{align}
  17. \sum_{i=1}^n f(x) &= ax^2 + bx + c \tikzmarkht{\sum^n}A \\
  18. ax^2 + bx + c &= g(x) \tikzmarkdp(B \\
  19. h(x) &= dx^3 + ex^2 + fx + h \tikzmark C \\
  20. dx^3 + ex^2 + fx + \frac12 &= i(x) \tikzmarkdp{\frac12}D
  21. \end{align}
  22. \tikz[remember picture,overlay,
  23. label distance=10pt,inner sep=0pt]{
  24. \node[fit=(A)(B),
  25. label={0:$\forall i\in N$\tikzmark E},
  26. right delimiter=\rbrace]{};
  27. \node[fit=(A)(E)(C)(D),
  28. label={0:$\forall t\in N$},
  29. right delimiter=\rbrace]{};
  30. }%
  31. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  32. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  33. \end{document}
复制代码
效果:
QQ截图20200308205610.png
这回为了精确地定位锚点,新定义了 \tikzmarkht 和 \tikzmarkdp ,用公式中最高或最低的东西来定点,像上图的第一条公式,就得用 \sum^n 来确定点 A。
改用 fit 来解决最右的位置,这样就不用看哪条公式长了,用 right delimiter 加括号(为此需添加 fit 和 matrix 库)。
在第一个括号的 label 的最后再加一个 tikzmark,用来确定第二个括号的位置,这样就无需调试水平距离了。
但是,由于需要第一个括号画好后才会知道 E 点的位置,所以以上代码在首次编译时需要编译三次才能画好,如果再多一层,就要再编译多一次(硬伤……),比如下面的,要编译四次
  1. \documentclass{article}
  2. \usepackage{amsmath}
  3. \usepackage{tikz}
  4. \usetikzlibrary{calc,fit,matrix}
  5. \newcommand\tikzmark[2][0,0]{%
  6. \tikz[baseline,remember picture,overlay]
  7. \coordinate (#2) at (#1);}
  8. \newsavebox\tmpbox
  9. \newcommand\tikzmarkht[2]{%
  10. \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,\ht\tmpbox]{#2}}
  11. \newcommand\tikzmarkdp[2]{%
  12. \sbox\tmpbox{$\displaystyle#1$}\tikzmark[0,-\dp\tmpbox]{#2}}
  13. \begin{document}
  14. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  15. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  16. \begin{align}
  17. \sum_{i=1}^n f(x) &= ax^2 + bx + c \tikzmarkht{\sum^n}A \\
  18. ax^2 + bx + c &= g(x) \tikzmarkdp(B \\
  19. h(x) &= dx^3 + ex^2 + fx + h \tikzmarkdp)C\\
  20. dx^3 + ex^2 + fx + \frac12 &= i(x) \tikzmarkdp{\frac12}D
  21. \end{align}
  22. \tikz[remember picture,overlay,
  23. label distance=10pt,inner sep=0pt]{
  24. \node[fit=(A)(B),
  25. label={0:$XXX$\tikzmark E},
  26. right delimiter=\rbrace]{};
  27. \node[fit=(A)(E)(C),
  28. label={0:$YYY$\tikzmark F},
  29. right delimiter=\rbrace]{};
  30. \node[fit=(A)(F)(D),
  31. label={0:$ZZZ$},
  32. right delimiter=\rbrace]{};
  33. \foreach \i in {A,B,C,D,E,F} {
  34. \fill[red] (\i) circle (1pt);
  35. \draw[red,{[sep=2pt]<}-] (\i)--+(30:0.5)node[right]{(\i)};
  36. }
  37. }%
  38. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  39. asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
  40. \end{document}
复制代码
效果:
QQ截图20200308212702.png
为了便于理解,我标注了各个锚点的位置。
但又有问题了,由于通过这种方式添加的东西是不占任何空间的,所以整个公式不会自动向左移,导致和右边的编号重叠了,还是得手工移……😭

哦还有,添加括号的语句得确保和公式在同一页,因此,如果公式刚好排到页底,括号有可能加到下一页,因此其实应该把它放到 align 里面写比较安全,不过懒得改了……

手机版|悠闲数学娱乐论坛(第3版)

GMT+8, 2025-3-4 15:30

Powered by Discuz!

× 快速回复 返回顶部 返回列表