在论坛上搜索了好一会儿后,我放弃了(我想我可以自己做),我在将密钥从l3keys
(以逗号分隔)传递给时遇到了问题tikz
。我创建了一个接受逗号分隔的参数的命令,并key=val
封装了tikz(mark)
生成如下学校示例:
命令如下
\tikzmkpd[config-A={yshift-A={#1}, end-yshift={#1,#2,#3},
color={#1,#2,#3}, yshift-A={#1}, distance={#1,#2,#3}
angle-star={#1,#2,#3}, angle-end={#1,#2,#3},
}]{A,B}{C,D,E}
接受以逗号分隔的参数的键都通过相同的函数传递,并且一切正常,除了color
键之外,当激活时我收到错误:
! Package PGF Math Error: Unknown function `gray' (in 'gray').
See the PGF Math package documentation for explanation.
Type H <return> for immediate help.
...
l.126 ...,yshift-A=15pt,color={gray,red}}]{A}{B,D}
该函数没有正确地划定界限,并且吸收了超过帐户的内容,将其余的参数传递给tikz
,奇怪的是,如果我在\keys_define:nn
其中定义相同的代码,它可以正常工作:
\keys_define:nn { tikzmkpd / config-A }
{
color .code:n = {
\clist_set:Nn \l_tmpa_clist { #1 }
\bool_if:nT { \int_compare_p:n { \clist_count:n { #1 } = 1 } }
{
\tl_set:Nx \l_colour_AC_tl { \clist_item:Nn \l_tmpa_clist {1} }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n { #1 } = 2 } }
{
\tl_set:Nx \l_colour_AC_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_colour_AD_tl { \clist_item:Nn \l_tmpa_clist {2} }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n { #1 } = 3 } }
{
\tl_set:Nx \l_colour_AC_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_colour_AD_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l_colour_AE_tl { \clist_item:Nn \l_tmpa_clist {3} }
}
},
}
这是我自己的代码,我尽可能地将其最小化,以便于理解(在我的原始文档中也有tikzmkpd / config-B
)
\documentclass{article}
\usepackage{xparse,tikz,etoolbox}
\usetikzlibrary{arrows.meta,bending,calc,tikzmark}
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}} % short :)
\makeatletter
\def\@colon{:} % active : for expl3
\ExplSyntaxOn
\cs_new_protected:Npn \__define_numeric_keys:nnnnnnnnn #1#2#3#4#5#6#7#8#9
{
\keys_define:nn { tkmdraw/config-#1 }
{
yshift-#1C .tl_set:c = {l_yshift_#1C_tl}, yshift-#1C .initial:n = #2,
yshift-#1D .tl_set:c = {l_yshift_#1D_tl}, yshift-#1D .initial:n = #3,
yshift-#1E .tl_set:c = {l_yshift_#1E_tl}, yshift-#1E .initial:n = #4,
distan-#1C .tl_set:c = {l_distan_#1C_tl}, distan-#1C .initial:n = #5,
distan-#1D .tl_set:c = {l_distan_#1D_tl}, distan-#1D .initial:n = #6,
distan-#1E .tl_set:c = {l_distan_#1E_tl}, distan-#1E .initial:n = #7,
angles-#1C .tl_set:c = {l_angles_#1C_tl}, angles-#1C .initial:n = #8,
angles-#1D .tl_set:c = {l_angles_#1D_tl}, angles-#1D .initial:n = #8,
angles-#1E .tl_set:c = {l_angles_#1E_tl}, angles-#1E .initial:n = #8,
anglee-#1C .tl_set:c = {l_anglee_#1C_tl}, anglee-#1C .initial:n = #9,
anglee-#1D .tl_set:c = {l_anglee_#1D_tl}, anglee-#1D .initial:n = #9,
anglee-#1E .tl_set:c = {l_anglee_#1E_tl}, anglee-#1E .initial:n = #9,
}
}
\__define_numeric_keys:nnnnnnnnn{A}{1.7ex}{1.7ex}{1.7ex}{1ex}{2ex}{3ex}{60}{120}
\cs_new_protected:Npn \__define_colour_keys:nnnn #1#2#3#4
{
\keys_define:nn { tkmdraw/config-#1 }
{
colour-#1C .tl_set:c = {l_colour_#1C_tl}, colour-#1C .initial:n = #2,
colour-#1D .tl_set:c = {l_colour_#1D_tl}, colour-#1D .initial:n = #3,
colour-#1E .tl_set:c = {l_colour_#1E_tl}, colour-#1E .initial:n = #4,
}
}
\__define_colour_keys:nnnn{A}{red}{green}{blue}
\keys_define:nn { tikzmkpd / config-A }
{
yshift-A .tl_set:c = {l_yshift_A_tl},%
yshift-A .initial:n = 1.7ex,
end-yshift .code:n = \__testkeys:nnn{A}{yshift}{#1},
angle-star .code:n = \__testkeys:nnn{A}{angles}{#1},
angle-end .code:n = \__testkeys:nnn{A}{anglee}{#1},
distance .code:n = \__testkeys:nnn{A}{distan}{#1},
color .code:n = \__testkeys:nnn{A}{colour}{#1},
}
\tl_new:N \l_tmpc_tl
\cs_new_protected:Npn \__testkeys:nnn #1#2#3
{
\clist_set:Nn \l_tmpa_clist { #3 }
\bool_if:nT { \int_compare_p:n { \clist_count:n { #3 } = 1 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\keys_set:nn { tkmdraw/config-#1 }
{ #2-#1C= \l_tmpa_tl, }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n { #3 } = 2 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\keys_set:nn { tkmdraw/config-#1 }
{ #2-#1C= \l_tmpa_tl, #2-#1D= \l_tmpb_tl, }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n { #3 } = 3 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l_tmpc_tl { \clist_item:Nn \l_tmpa_clist {3} }
\keys_set:nn { tkmdraw/config-#1 }
{ #2-#1C= \l_tmpa_tl, #2-#1D= \l_tmpb_tl, #2-#1E= \l_tmpc_tl,}
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \_case_one:n
{
\draw[->,\use:c{l_colour_AC_tl}]
([yshift=\use:c{l_yshift_A_tl}]$(pic ~ cs\@colon\csuse{A1})$)
to[out=\use:c{l_angles_AC_tl},in=\use:c{l_anglee_AC_tl},distance=\use:c{l_distan_AC_tl}]
([yshift=\use:c{l_yshift_AC_tl}]$(pic ~ cs\@colon\csuse{B1})$);
\draw[->,\use:c{l_colour_AD_tl}] %,
([yshift=\use:c{l_yshift_A_tl}]$(pic ~ cs\@colon\csuse{A1})$)
to[out=\use:c{l_angles_AD_tl},in=\use:c{l_anglee_AD_tl},distance=\use:c{l_distan_AD_tl}]
([yshift=\use:c{l_yshift_AD_tl}]$(pic ~ cs\@colon\csuse{B2})$);
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \_case_two:n
{
\_case_one:n
\draw[->,\use:c{l_colour_AE_tl}]
([yshift=\use:c{l_yshift_A_tl}]$(pic ~ cs\@colon\csuse{A1})$)
to[out=\use:c{l_angles_AE_tl},in=\use:c{l_anglee_AE_tl},distance=\use:c{l_distan_AE_tl}]
([yshift=\use:c{l_yshift_AE_tl}]$(pic ~ cs\@colon\csuse{B3})$);
}
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } { #1 } },
}
\NewDocumentCommand{\tikzmkpd}{O{} m m}
{
\group_begin:
\IfNoValueF { #1 } { \keys_set:nn { tikzmkpd }{ #1 } }
\foreach \x [count=\n] in {#2} { \csxdef{A\n}{\x} }% save in A<n>
\foreach \y [count=\m] in {#3} { \csxdef{B\m}{\y} }% save in B<m>
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}
\begin{tikzpicture}[overlay,remember ~ picture]%
\bool_if:nT { \int_compare_p:n { \clist_count:n { #2 } = 1 } &&
\int_compare_p:n { \clist_count:n { #3 } = 2 } } { \_case_one:n }
\bool_if:nT { \int_compare_p:n { \clist_count:n { #2 } = 1 } &&
\int_compare_p:n { \clist_count:n { #3 } = 3 } } { \_case_two:n }
\end{tikzpicture}
\group_end:
}
\ExplSyntaxOff
\makeatother
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={end-yshift={15pt,15pt},yshift-A=15pt,color={gray,red}}]{A}{B,D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$
\tikzmkpd[config-A={color={gray,gray,gray},end-yshift={5pt,5pt,5pt}}]{a1}{b1,c1,d1}
\end{document}
有什么想法可以解决它吗?......(我的想法是尽量少重复类似的代码)
问候。
答案1
这不是一个最小的例子,这里有十个不同的问题!下面给出的代码有效。按照请求你的评论,为了更好地遵守 LaTeX3 编码约定(据我所知),我做出了比严格必要的更多的更改。
请注意,_private_
中的命名方案\keys_define:nn { tikzmkpd/_private_/config-#1 }
是我发明的;我不知道是否存在针对这种情况的标准命名方案。我这样做是因为我相信在此层次结构下定义的键是宏的实现细节,不应由“用户”直接使用。
LaTeX3 编码约定如下expl3.pdf,l3styleguide.pdf在界面3.pdf。那里建议的缩进样式与您的略有不同(特别是,它使用了两个空格的基本偏移量)。但下面的代码已经相当易读,所以我让您自己决定是否也严格遵循缩进指南。
对于函数,我使用了:
\__tikzmkpd_
私有的前缀;\tikzmkpd_
公共的前缀(仅,我将其添加为与您已经定义的\tikzmkpd:nnn
用户层命令相对应的编程层后端函数)。\tikzmkpd
这样,就可以很容易地将所有这些代码转换为一个可以与 LaTeX 生态系统的其余部分很好地兼容的包。您的\_case_one:n
和\_case_two:n
函数名称不正确,原因有两个:
- 前缀;
- 后缀
:n
表示他们应该接受论点,但实际上却没有。
我将这两个函数分别重命名为\__tikzmkpd_case_one:
和\__tikzmkpd_case_two:
。
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, bending, calc, tikzmark}
\ExplSyntaxOn
\cs_new_protected:Npn \__tikzmkpd_define_numeric_keys:nnnnnnnnn
#1#2#3#4#5#6#7#8#9
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
yshift-#1C .tl_set:c = { l_yshift_#1C_tl }, yshift-#1C .initial:n = {#2},
yshift-#1D .tl_set:c = { l_yshift_#1D_tl }, yshift-#1D .initial:n = {#3},
yshift-#1E .tl_set:c = { l_yshift_#1E_tl }, yshift-#1E .initial:n = {#4},
distan-#1C .tl_set:c = { l_distan_#1C_tl }, distan-#1C .initial:n = {#5},
distan-#1D .tl_set:c = { l_distan_#1D_tl }, distan-#1D .initial:n = {#6},
distan-#1E .tl_set:c = { l_distan_#1E_tl }, distan-#1E .initial:n = {#7},
angles-#1C .tl_set:c = { l_angles_#1C_tl }, angles-#1C .initial:n = {#8},
angles-#1D .tl_set:c = { l_angles_#1D_tl }, angles-#1D .initial:n = {#8},
angles-#1E .tl_set:c = { l_angles_#1E_tl }, angles-#1E .initial:n = {#8},
anglee-#1C .tl_set:c = { l_anglee_#1C_tl }, anglee-#1C .initial:n = {#9},
anglee-#1D .tl_set:c = { l_anglee_#1D_tl }, anglee-#1D .initial:n = {#9},
anglee-#1E .tl_set:c = { l_anglee_#1E_tl }, anglee-#1E .initial:n = {#9},
}
}
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ A } { 1.7ex } { 1.7ex } { 1.7ex } { 1ex } { 2ex } { 3ex } { 60 } { 120 }
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ B }{ -0.5ex }{ -0.5ex }{ -0.5ex } { 1ex } { 2ex } { 3ex } {-60 } {-120 }
\cs_new_protected:Npn \__tikzmkpd_define_colour_keys:nnnn #1#2#3#4
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
colour-#1C .tl_set:c = { l_colour_#1C_tl }, colour-#1C .initial:n = {#2},
colour-#1D .tl_set:c = { l_colour_#1D_tl }, colour-#1D .initial:n = {#3},
colour-#1E .tl_set:c = { l_colour_#1E_tl }, colour-#1E .initial:n = {#4},
}
}
\__tikzmkpd_define_colour_keys:nnnn { A } { red } { green } { blue }
\__tikzmkpd_define_colour_keys:nnnn { B } { red } { green } { blue }
\keys_define:nn { tikzmkpd / config-A }
{
yshift-A .tl_set:c = { l_yshift_A_tl },
yshift-A .initial:n = { 1.7ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { colour } {#1} },
raise .meta:n = { yshift-A = {#1}, end-yshift = {#1,#1,#1} },
}
\keys_define:nn { tikzmkpd / config-B }
{
yshift-B .tl_set:c = { l_yshift_B_tl },
yshift-B .initial:n = { -0.5ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { colour } {#1} },
raise .meta:n = { yshift-B = {#1}, end-yshift = {#1,#1,#1} },
}
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
\cs_new:Npn \__tikzmkpd_subs_ii:nnnn #1#2#3#4
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4} } }
\cs_new:Npn \__tikzmkpd_subs_iii:nnnnn #1#2#3#4#5
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4}, #1-#2E= {#5} } }
\cs_generate_variant:Nn \__tikzmkpd_subs_i:nnn { nnV }
\cs_generate_variant:Nn \__tikzmkpd_subs_ii:nnnn { nnVV }
\cs_generate_variant:Nn \__tikzmkpd_subs_iii:nnnnn { nnVVV }
\cs_generate_variant:Nn \keys_set:nn { nx }
\tl_new:N \l__tikzmkpd_tmp_tl
\cs_new_protected:Npn \__tikzmkpd_set_subkeys:nnn #1#2#3
{
\clist_set:Nn \l_tmpa_clist {#3}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 1 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_i:nnV {#2} {#1} \l_tmpa_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 2 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_ii:nnVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 3 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l__tikzmkpd_tmp_tl { \clist_item:Nn \l_tmpa_clist {3} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_iii:nnVVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl
\l__tikzmkpd_tmp_tl }
}
}
\seq_new:N \l__tikzmkpd_mycmd_seq
\cs_new_protected:Npn \__tikzmkpd_store_node_names:nn #1#2
{
\seq_set_from_clist:Nn \l__tikzmkpd_mycmd_seq {#2}
\seq_indexed_map_inline:Nn \l__tikzmkpd_mycmd_seq
{
\tl_clear_new:c { l__tikzmkpd_nodename_#1##1_tl }
\tl_set:cn { l__tikzmkpd_nodename_#1##1_tl } {##2}
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_one:
{
\draw[->, \use:c{l_colour_AC_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AC_tl}, in=\use:c{l_anglee_AC_tl},
distance=\use:c{l_distan_AC_tl}]
([yshift=\use:c{l_yshift_AC_tl}] \tl_use:c { l__tikzmkpd_nodename_B1_tl });
\draw[->,\use:c{l_colour_AD_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AD_tl}, in=\use:c{l_anglee_AD_tl},
distance=\use:c{l_distan_AD_tl}]
([yshift=\use:c{l_yshift_AD_tl}] \tl_use:c { l__tikzmkpd_nodename_B2_tl });
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_two:
{
\__tikzmkpd_case_one:
\draw[->, \use:c{l_colour_AE_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AE_tl}, in=\use:c{l_anglee_AE_tl},
distance=\use:c{l_distan_AE_tl}]
([yshift=\use:c{l_yshift_AE_tl}] \tl_use:c { l__tikzmkpd_nodename_B3_tl });
}
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } {#1} },
config-B .code:n = { \keys_set:nn { tikzmkpd / config-B } {#1} },
}
\cs_new_protected:Npn \tikzmkpd:nnn #1#2#3
{
\group_begin:
\keys_set:nn { tikzmkpd } {#1}
\__tikzmkpd_store_node_names:nn {A} {#2}
\__tikzmkpd_store_node_names:nn {B} {#3}
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}
\begin{tikzpicture}[overlay, remember ~ picture]
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_one: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_two: }
\end{tikzpicture}
\group_end:
}
\NewDocumentCommand \tikzmkpd { O{} m m }
{
\tikzmkpd:nnn {#1} {#2} {#3}
}
\ExplSyntaxOff
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}} % short :)
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={end-yshift={8pt,9pt}, yshift-A=8pt, color={gray,red}}]%
{A}{B, D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$%
\tikzmkpd[config-A={color={gray,gray,gray}, end-yshift={5pt,5pt,5pt}}]%
{a1}{b1, c1, d1}
\end{document}
我测试了上述代码,它给出了下面的截图。在文章的最后,你会发现一个改进的 Pablo 变体,它处理了更多乘法分配律的情况(“一”到“四”的情况,而不仅仅是“一”和“二”的情况)。然而,我自己无法完全验证这个版本,因为它显然依赖于 PGF/Ti 的最新错误修复或功能钾Z—对于我这里的版本来说太新了,即2019/02/02 v3.1.1
。
我相信你可以在调试方法方面取得进展:你是否测试过你的每一个功能,你会这样做:
\tl_show:N \l_yshift_AC_tl
\tl_show:N \l_yshift_AD_tl
\tl_show:N \l_colour_AC_tl
\tl_show:N \l_colour_AD_tl
调用之后\keys_set:nn { tikzmkpd } {#1}
,这表明你的\__testkeys:nnn
(现在调用的\__tikzmkpd_set_subkeys:nnn
)没有正常工作。主要问题是你传递了单个令牌,例如\l_tmpa_tl
在参数中,而你实际上希望它们的价值(相当于扩展\l_tmpa_tl
或的结果\tl_use:N \l_tmpa_tl
;看看我怎么做的)。此外,在某些地方,如果某些参数值包含逗号,则需要更多括号。例如,这个:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ #1-#2C = {#3}, }
比这个更好:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ #1-#2C= #3, }
以防万一#3
包含逗号。事实上,除非你打算在#1
,#2
或中使用宏#3
,否则以下做法可能更可取,以避免不必要的扩展(因为我们稍后会在参数中使用它x
),这就是我上面所做的:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
另一个导致代码无法运行的问题是,对于使用 创建的节点\tikzmarknode
,pic cs
您使用的语法不起作用 — 至少在我的设置中是这样。好消息是,这可以大大简化(请参阅我对 和\_case_one:n
的更改\_case_two:n
[现在重命名为\__tikzmkpd_case_one:
和\__tikzmkpd_case_two:
])。
你的问题太复杂了,有那么多参数,TikZ 代码和 代码混在一起l3keys
,我担心没人会重复使用我的答案。:-( 我并不批评使用 来l3keys
进行 TikZ 工作(首先,我自己用 比 更舒服l3keys
)pgfkeys
,但为了这个网站其他用户的利益,我认为你应该把解析问题和 TikZ 问题区分开来——因为人们已经告诉过你了。
你的 LaTeX 编码技能看起来不错;我的主要建议是:
阅读更多文档,特别是有关 LaTeX3 命名约定、扩展和变体的文档(请参阅界面3.pdf)。
每当你再次遇到这样的问题时,请使用
\tracingmacros=1 \tracingonline=1\relax
,如果这还不足以理解发生了什么,请打印你的函数准备的每个“东西”的值1(针对你的每个函数)。例如,在尝试排版 之前,打印你将在其中使用的所有选项和所有参数。这种方法可以帮助你找到你的(现在重命名为)tikzpicture
中的错误。\__testkeys:nnn
\__tikzmkpd_set_subkeys:nnn
正如承诺的那样,以下是 Pablo 添加的扩展代码:
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, bending, calc, tikzmark}
\ExplSyntaxOn
\cs_new_protected:Npn \__tikzmkpd_define_numeric_keys:nnnnnnnnn
#1#2#3#4#5#6#7#8#9
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
yshift-#1C .tl_set:c = { l_yshift_#1C_tl }, yshift-#1C .initial:n = {#2},
yshift-#1D .tl_set:c = { l_yshift_#1D_tl }, yshift-#1D .initial:n = {#3},
yshift-#1E .tl_set:c = { l_yshift_#1E_tl }, yshift-#1E .initial:n = {#4},
distan-#1C .tl_set:c = { l_distan_#1C_tl }, distan-#1C .initial:n = {#5},
distan-#1D .tl_set:c = { l_distan_#1D_tl }, distan-#1D .initial:n = {#6},
distan-#1E .tl_set:c = { l_distan_#1E_tl }, distan-#1E .initial:n = {#7},
angles-#1C .tl_set:c = { l_angles_#1C_tl }, angles-#1C .initial:n = {#8},
angles-#1D .tl_set:c = { l_angles_#1D_tl }, angles-#1D .initial:n = {#8},
angles-#1E .tl_set:c = { l_angles_#1E_tl }, angles-#1E .initial:n = {#8},
anglee-#1C .tl_set:c = { l_anglee_#1C_tl }, anglee-#1C .initial:n = {#9},
anglee-#1D .tl_set:c = { l_anglee_#1D_tl }, anglee-#1D .initial:n = {#9},
anglee-#1E .tl_set:c = { l_anglee_#1E_tl }, anglee-#1E .initial:n = {#9},
}
}
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ A } { 1.7ex } { 1.7ex } { 1.7ex } { 1ex } { 2ex } { 3ex } { 60 } { 120 }
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ B }{ -0.5ex }{ -0.5ex }{ -0.5ex } { 1ex } { 2ex } { 3ex } {-60 } {-120 }
\cs_new_protected:Npn \__tikzmkpd_define_colour_keys:nnnn #1#2#3#4
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
colour-#1C .tl_set:c = { l_colour_#1C_tl }, colour-#1C .initial:n = {#2},
colour-#1D .tl_set:c = { l_colour_#1D_tl }, colour-#1D .initial:n = {#3},
colour-#1E .tl_set:c = { l_colour_#1E_tl }, colour-#1E .initial:n = {#4},
}
}
\__tikzmkpd_define_colour_keys:nnnn { A } { red } { green } { blue }
\__tikzmkpd_define_colour_keys:nnnn { B } { red } { green } { blue }
\keys_define:nn { tikzmkpd / config-A }
{
yshift-A .tl_set:c = { l_yshift_A_tl },
yshift-A .initial:n = { 1.7ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { colour } {#1} },
raise .meta:n = { yshift-A = {#1}, end-yshift = {#1,#1,#1} },
}
\keys_define:nn { tikzmkpd / config-B }
{
yshift-B .tl_set:c = { l_yshift_B_tl },
yshift-B .initial:n = { -0.5ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { colour } {#1} },
raise .meta:n = { yshift-B = {#1}, end-yshift = {#1,#1,#1} },
}
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
\cs_new:Npn \__tikzmkpd_subs_ii:nnnn #1#2#3#4
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4} } }
\cs_new:Npn \__tikzmkpd_subs_iii:nnnnn #1#2#3#4#5
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4}, #1-#2E= {#5} } }
\cs_generate_variant:Nn \__tikzmkpd_subs_i:nnn { nnV }
\cs_generate_variant:Nn \__tikzmkpd_subs_ii:nnnn { nnVV }
\cs_generate_variant:Nn \__tikzmkpd_subs_iii:nnnnn { nnVVV }
\cs_generate_variant:Nn \keys_set:nn { nx }
\tl_new:N \l__tikzmkpd_tmp_tl
\cs_new_protected:Npn \__tikzmkpd_set_subkeys:nnn #1#2#3
{
\clist_set:Nn \l_tmpa_clist {#3}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 1 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_i:nnV {#2} {#1} \l_tmpa_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 2 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_ii:nnVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 3 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l__tikzmkpd_tmp_tl { \clist_item:Nn \l_tmpa_clist {3} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_iii:nnVVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl
\l__tikzmkpd_tmp_tl }
}
}
\seq_new:N \l__tikzmkpd_mycmd_seq
\cs_new_protected:Npn \__tikzmkpd_store_node_names:nn #1#2
{
\seq_set_from_clist:Nn \l__tikzmkpd_mycmd_seq {#2}
\seq_indexed_map_inline:Nn \l__tikzmkpd_mycmd_seq
{
\tl_clear_new:c { l__tikzmkpd_nodename_#1##1_tl }
\tl_set:cn { l__tikzmkpd_nodename_#1##1_tl } {##2}
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_one:
{
\draw[->, \tl_use:c{l_colour_AC_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AC_tl}, in=\tl_use:c{l_anglee_AC_tl},
distance=\tl_use:c{l_distan_AC_tl}]
([yshift=\tl_use:c{l_yshift_AC_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B1_tl})$);
\draw[->,\tl_use:c{l_colour_AD_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AD_tl}, in=\tl_use:c{l_anglee_AD_tl},
distance=\tl_use:c{l_distan_AD_tl}]
([yshift=\tl_use:c{l_yshift_AD_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B2_tl})$);
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_two:
{
\__tikzmkpd_case_one:
\draw[->, \tl_use:c{l_colour_AE_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AE_tl}, in=\tl_use:c{l_anglee_AE_tl},
distance=\tl_use:c{l_distan_AE_tl}]
([yshift=\tl_use:c{l_yshift_AE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
}
% case 3: (a+b)(c+d) (A1+A2)(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_three:
{
\__tikzmkpd_case_one:
\draw[->,\tl_use:c{l_colour_BC_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BC_tl},in=\tl_use:c{l_anglee_BC_tl},
distance=\tl_use:c{l_distan_BC_tl}]
([yshift=\tl_use:c{l_yshift_BC_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B1_tl})$);
\draw[->,\tl_use:c{l_colour_BD_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BD_tl},in=\tl_use:c{l_anglee_BD_tl},
distance=\tl_use:c{l_distan_BD_tl}]
([yshift=\tl_use:c{l_yshift_BD_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B2_tl})$);
}
% case 4: (a+b)(c+d+e) (A1+A2)(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_four:
{
\__tikzmkpd_case_three:
\draw[->,\tl_use:c{l_colour_AE_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AE_tl},in=\tl_use:c{l_anglee_AE_tl},
distance=\tl_use:c{l_distan_AE_tl}]
([yshift=\tl_use:c{l_yshift_AE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
\draw[->,\tl_use:c{l_colour_BE_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BE_tl},in=\tl_use:c{l_anglee_BE_tl},
distance=\tl_use:c{l_distan_BE_tl}]
([yshift=\tl_use:c{l_yshift_BE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
}
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } {#1} },
config-B .code:n = { \keys_set:nn { tikzmkpd / config-B } {#1} },
}
\cs_new_protected:Npn \tikzmkpd:nnn #1#2#3
{
\group_begin:
\keys_set:nn { tikzmkpd } {#1}
\__tikzmkpd_store_node_names:nn {A} {#2}
\__tikzmkpd_store_node_names:nn {B} {#3}
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}
\begin{tikzpicture}[overlay, remember ~ picture]
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_one: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_two: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 2 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_three: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 2 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_four: }
\end{tikzpicture}
\group_end:
}
\NewDocumentCommand \tikzmkpd { O{} m m }
{
\tikzmkpd:nnn {#1} {#2} {#3}
}
\ExplSyntaxOff
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}} % short :)
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={raise=12pt}]%
{A}{B, D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$%
\tikzmkpd[config-A={color={gray,gray,gray}, end-yshift={5pt,5pt,5pt}}]%
{a1}{b1, c1, d1}
\section{case 3}
$(\TkM{X1}{2a^2}+\TkM{X2}{n})(\TkM{Y1}{b}+\TkM{Y2}{3q})$%
\tikzmkpd{X1,X2}{Y1,Y2}
\section{case 4}
$(\TkM{a}{x}-\TkM{b}{2})(\TkM{c}{x^2}+\TkM{d}{2x}+\TkM{e}{4})$
\tikzmkpd[config-B={end-yshift={-15pt,-15pt},color={gray,red}}]{a,b}{c, d, e}
\tikzmkpd[config-A={raise=4pt,color={gray,gray,gray}}]%
{A}{B, D}
\end{document}
脚注
- 对于这样的临时代码,您可以使用 TeX 或 LaTeX2e 命令(例如
\show
或 )\typeout
,以及 LaTeX3 命令(例如\tl_show:N
或 )\box_show:N
。