参数化标记

参数化标记

假设我定义一种添加一些标记的样式,例如如下:

\begin{tikzpicture}[
        mymarks/.style = {
            postaction = {
                decorate,
                decoration = {markings, mark = at position 0.5 with {\arrow[red]{>};}},
            },
        },
    ]
    \draw[mymarks] (0, 0) -- (1, 0);
\end{tikzpicture}

如何参数化这种样式?即如何使颜色“红色”成为可自定义的参数?当然,一种简单直接的方法是使用键值并写入\arrow[#1]mymarks=red。但是,如果键值已经用于其他用途并且颜色参数无论如何都应该是可选的,该怎么办?

一个想法是定义mymarks/color/.store in = \param并编写\arrow[\param]\draw[mymarks/color=red, mymarks],但随后我需要自己为每个这样的参数创建一个全局宏。

另一个想法是定义一些内容mymarks/color/.initial = red并将其用作\arrow[\pgfkeysvalueof{/tikz/mymarks/color}]。但是,是否有某种方法可以像定义后置操作时那样创建本地快捷方式,这样如果多次使用该值,\path let我就不必一直写入?\pgfkeysvalueof{/tikz/mymarks/color}

有没有更好的方法来实现这种参数化?

答案1

当然,您可以定义一个宏,它只是 的包装器\pgfkeysvalueof,最短的“宏”是~(a)活动字符,b)通常用于不间断空格)。在箭头内标记不间断空格是不需要的。因此,您可以说:

\begin{tikzpicture}[
  /pgf/decoration/tilde shortcut/.code = 
    \def~##1{\pgfkeysvalueof{/tikz/mymarks/##1}},
  mymarks/.default = ,
  mymarks/.style = {
    postaction = {
      decorate,
      decoration = {
        markings, tilde shortcut,
        mark = at position .5 with {\arrow[~{color}]{>}},
      }
    }
  },
  mymarks/color/.initial=red,
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[mymarks/color=green, mymarks] (0, 0) -- (1, .2) node[right]{x~y};
\end{tikzpicture}

如您所见,~当我们回到时,它具有其正常定义node

但由于你只定义mymarks一次样式,我认为你不需要使用快捷方式。(尽管,也许

\newcommand*\mymarksvo[1]{\pgfkeysvalueof{/tikz/mymarks/#1}}

够简短且独特吗?


我甚至想更进一步。在这里,我们定义一个mymarks键,该键可选地接受键/值列表并将它们应用于/tikz/mymarks名称空间:

\begin{tikzpicture}[
  mymarks/.default = ,
  mymarks/.style = {
    postaction = {
      decorate,
      decoration = {
        markings,
        /utils/exec=\pgfqkeys{/tikz/mymarks}{#1},
        my mark/.style = {
          mark = at position ########1 with {%
            \arrow[style/.expand twice/.expand once =
              \pgfkeysvalueof{/tikz/mymarks/style}
            ]{>}
          }
        },
        my mark/.list/.expand twice/.expand once=
          \pgfkeysvalueof{/tikz/mymarks/pos}
      },
    },
  },
  mymarks/pos/.initial=.5,
  mymarks/style/.initial=red,
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
  mymarks={
    pos={.2, .4, ..., .8},
    style={scale=2, rotate=-90}
  }
] (0, 0) -- (1, .2);
\end{tikzpicture}

这样你就不需要(但仍然可以)做mymarks/pos = …mymarks/style = …除了它本身之外mymarks,你只需说

mymarks = {pos = …, style = …}

/tikz/style中使用的键\arrow仅定义为style/.style = {#1},即它与使用完全相同,#1但是我们现在可以在#1使用它之前对其进行一些操作,否则我们无法做到这一点。在这种情况下:扩展。)

我们自己的/tikz/mymarks/style密钥(不是样式但值键)的使用有些不寻常。(我们可以使用style/.append = …将键附加到此值,因此我们几乎可以以与使用实际样式相同的方式使用它。)


适当的风格可能更好。我们定义一个/tikz/mymarks/every arrow风格,现在需要覆盖它

mymarks = {every arrow/.style = …}

或者如果我们不想丢失以前的设​​置,请附加到:

mymarks = {every arrow/.append style = …}

PGF/TikZ 及其基础上构建的包/库通常还定义一个arrows附加到的键every arrow

\begin{tikzpicture}[
  /pgf/decoration/mymarks/.style = {
    mark = at position #1 with {\arrow[mymarks/every arrow]{>}}},
  mymarks/.default = ,
  mymarks/.style = {
    postaction = {
      decorate,
      decoration = {
        markings,
        /utils/exec=\pgfqkeys{/tikz/mymarks}{#1},
        mymarks/.list/.expand twice/.expand once=
          \pgfkeysvalueof{/tikz/mymarks/pos}
      },
    },
  },
  mymarks/pos/.initial=.5,
  mymarks/every arrow/.style=red,
  mymarks/arrows/.style={every arrow/.append style={#1}}
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
  mymarks={
    pos={.2, .4, ..., .8},
    arrows={scale=2, rotate=-90}% still red
  }
] (0, 0) -- (1, .2);
\end{tikzpicture}

现在.expand twice/.expand once有点笨重,我们可以定义自己的.expand thrice处理程序...或者使用给定键的值的处理程序...或者甚至更短的处理程序:

\makeatletter
\pgfqkeys{/handlers}{
  .expand thrice/.code=%
    \pgfkeysalso{\pgfkeyscurrentpath/.expand twice/.expand once={#1}},
  .value/.code=%
    \pgfkeysgetvalue{#1}\pgfkeys@temp
    \expandafter\pgfkeys@exp@call\expandafter{\pgfkeys@temp},%
  .tikz value/.code=\pgfkeysalso{\pgfkeyscurrentpath/.value=/tikz/#1},
  .../.code=\pgfkeysalso{\pgfkeyscurrentpath/.value=/tikz/mymarks/#1},
}
\makeatother

现在你可以做以下任何一件事:

my mark/.list/.expand thrice = \pgfkeysvalueof{/tikz/mymarks/pos}
my mark/.list/.value = /tikz/mymarks/pos
my mark/.list/.tikz value = mymarks/pos
my mark/.list/... = pos

不过,类似于~我只定义...本地。


但我们可以进一步推动这一进程……

代码

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings,arrows.meta}
\makeatletter
\pgfqkeys{/handlers}{
  .value/.code=%
    \pgfkeysgetvalue{#1}\pgfkeys@temp
    \expandafter\pgfkeys@exp@call\expandafter{\pgfkeys@temp}%
    % this is equivalent to:
    % \pgfkeysalso{\pgfkeyscurrentpath/.expand once=\pgfkeys@temp}
}
\makeatother
\begin{document}
\begin{tikzpicture}[
  /pgf/decoration/my mark/.style = {
    /utils/exec=\edef\mymarkscounter{\the\numexpr\mymarkscounter+1\relax},
    mark/.expanded = at position #1 with {\noexpand\arrow[
        mymarks/every arrow,
        mymarks/arrow \mymarkscounter/.try
      ]{>}
    }% expanded is needed since "mark" only collects
  },
  mymarks/.default = ,
  mymarks/.style = {
    postaction = {
      decorate,
      decoration = {
        markings,
        /utils/exec=\pgfqkeys{/tikz/mymarks}{#1}\def\mymarkscounter{0},
        my mark/.list/.value=/tikz/mymarks/pos
      }
    }
  },
  mymarks/pos/.initial=.5, mymarks/every arrow/.style=red,
  % to be on the safe site we use the full path so that we can do
  % \tikzset{mymarks/arrows=…}
  % where we don't want to reder to /tikz/every arrow
  mymarks/arrows/.style={/tikz/mymarks/every arrow/.append style={#1}}
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
  mymarks={
    pos={.2, .4, ..., .8},
    arrows = {scale = 2, rotate = -90},
    arrow 3/.style = blue,
    arrow 2/.style = {green, > = {Stealth[round]}}
  }
] (0, 0) -- (1, .2);
\end{tikzpicture}
\end{document}

相关内容