使用 pgfkeys 绘制 TikZ 路径

使用 pgfkeys 绘制 TikZ 路径

考虑以下 MWE:

\documentclass[border=1cm]{standalone}
\usepackage{tikz}

\tikzset{
    first/.style = {
        draw,
        ultra thick,
        red,
    },
    second/.style = {
        draw,
        ultra thin,
        blue,
        >=latex,
        ->
    }
}

\makeatletter

\pgfdeclareshape{symbol}{
  \savedanchor{\southwest}{\pgfpoint{-0.5cm}{-0.5cm}}
  \savedanchor{\northeast}{\pgfpoint{0.5cm}{0.5cm}}
  \inheritanchorborder[from=rectangle]
  \anchor{north}{\pgfpoint{0}{0.25cm}}
  \inheritanchor[from=rectangle]{east}
  \anchor{south}{\pgfpoint{0}{-0.25cm}}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{center}
  \anchor{inner east}{\pgfpoint{0.5cm - 0.4pt}{0}}
  \anchor{text}{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox+.5\dp\pgfnodeparttextbox}}

  \backgroundpath{
    \pgfkeys{/tikz/.cd, first}

    \pgfpathmoveto{\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep} }{0.5cm - (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep} }}
    \pgfpathlineto{\pgfpoint{0.5cm - sqrt(5)*\pgfkeysvalueof{/pgf/outer xsep} }{0}}
    \pgfpathlineto{\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep} }{-0.5cm + (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep} }}
    \pgfpathclose

    \pgfkeys{/tikz/.cd, second}
    \pgfpathmoveto{\pgfpoint{-0.25cm}{-0.5cm}}
    \pgfpathlineto{\pgfpoint{0.25cm}{0.5cm}}
  }
}


\makeatother

\begin{document}
    \begin{tikzpicture}
        \node (a) at (0,0) [symbol] {};
    \end{tikzpicture}
\end{document}

这是使用上述代码生成的结果:

在此处输入图片描述

我希望能够使用我的两个单独的 TikZ 样式分别配置三角形和线条的外观。因此,我实际上希望三角形超粗且为红色,而单条直线应超细、蓝色且配有箭头。

为什么不是这样,我该怎么改?我已经试过了,\pgfusepath{stroke}没有效果。

答案1

TikZ 使用 PGF 进行所有绘制,这并不奇怪。然而,形状的主要两条路径,\backgroundpath(背景,因为它将被绘制在文本后面)及其\foregroundpath(在文本前面),应该由用户“使用”\pgfnode(每一个\pgfnode都是\pgfmultipartnode只有一个节点部分):

\pgfnode{<shape>}{<anchor>}{<Text>}{<name of node>}{<do something with me>}

<do something with me>部分与正常路径上发生的事情相同,通常至少

\pgfusepath{stroke}

绘制形状的路径。

现在,当 TikZ 构建路径(\path和之间的所有内容;)时,除了围绕“笔”(--,,.. controls …...)移动和变换之外,它不会做太多事情,因为像draw和这样的键fill只是将它们的操作存储在另一个内部宏中。

只有;达到时,真正的魔法才会真正发生。存储的选项和设置会被执行,内容会被整理(剪辑?填充?绘制?阴影?淡入淡出?路径图片?双重?前置和后置操作?),错误消息会被调用等等。

因此,当 TikZ 找到时,;它将执行\tikz@finish
并且当 TikZ 添加节点时也将使用此宏,因为节点的路径应该与 PGF/TikZ 中的任何其他路径相同:

 \pgfmultipartnode{<shape>}{<anchor>}{<name of node>}{%
              \pgfutil@tempdima=\pgflinewidth%
              {\begingroup\tikz@finish}%
              \global\pgflinewidth=\pgfutil@tempdima%
            }%

它对线宽进行了一些调整,我假设它恢复了路径的线宽,因为\tikz@finish可能全局将其设置为其他值。

因为\tikz@finish(记住,;)还会关闭启动的组\path,所以需要一个\begingroup。 (这些设置是预先设置的,但在这个实际上不执行任何操作的组内仍然有效。)


长话短说,你需要指示你的形状使用 er \tikz@finish

这可能只是

\backgroundpath{%
  \begingroup
    \tikzset{first}%
    \pgfpathmoveto
      {\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep}}
                { 0.5cm - (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep}}}%
    \pgfpathlineto
      {\pgfpoint{0.5cm - sqrt(5)*\pgfkeysvalueof{/pgf/outer xsep}}{0pt}}%
    \pgfpathlineto
      {\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep}}
                {-0.5cm + (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep}}}%
    \pgfpathclose
  \tikz@finish
  \begingroup
    \tikzset{second}%
    \pgfpathmoveto{\pgfqpoint{-0.25cm}{-0.5cm}}%
    \pgfpathlineto{\pgfqpoint{0.25cm}{0.5cm}}%
  \tikz@finish
}

不需要\begingroup\tikzset{first}位于路径的开头,除非您想使用变换和其他花哨的东西来实际改变路径。但由于您只使用draw、线宽和颜色,因此也可以这样做:

\pgfpathmoveto{\pgfqpoint{-0.25cm}{-0.5cm}}%
\pgfpathlineto{\pgfqpoint{0.25cm}{0.5cm}}%
\begingroup
  \tikzset{second}%
\tikz@finish

(转型实际上需要\let\tikz@transform\relax努力,但那是另一回事。)

因此我们实际上有三条路径:firstsecond和 TikZ 通过调用 完成的空路径\pgfmultinodepart


最好将这些内容移到其他路径中,这样形状就可以明确地执行某些操作(描边、填充等),而不是使用用户应该“使用”的路径之一。但这一切都取决于您的实际用例 - 以及您的用户是谁。


也就是说,pic可能是更好的选择,但这也取决于用例。

代码

\documentclass[border=1mm, tikz]{standalone}
\tikzset{
  first/.style  = {draw, ultra thick, red},
  second/.style = {draw, ultra thin, blue, >=latex, ->}}
\makeatletter
\pgfdeclareshape{symbol}{
  \savedanchor{\southwest}{\pgfqpoint{-0.5cm}{-0.5cm}}
  \savedanchor{\northeast}{\pgfqpoint{0.5cm}{0.5cm}}
  \inheritanchorborder[from=rectangle]
  \anchor{north}{\pgfqpoint{0pt}{0.25cm}}
  \inheritanchor[from=rectangle]{east}
  \anchor{south}{\pgfqpoint{pt0}{-0.25cm}}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{center}
  \anchor{inner east}{\pgfpoint{0.5cm - 0.4pt}{+0pt}}
  \anchor{text}{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox+.5\dp\pgfnodeparttextbox}}
  \backgroundpath{%
    \begingroup
      % \let\tikz@transform\relax if you want transformations to work
      \tikzset{first}%
      \pgfpathmoveto
        {\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep}}
                  { 0.5cm - (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep}}}%
      \pgfpathlineto
        {\pgfpoint{0.5cm - sqrt(5)*\pgfkeysvalueof{/pgf/outer xsep}}{0pt}}%
      \pgfpathlineto
        {\pgfpoint{-0.5cm + \pgfkeysvalueof{/pgf/outer xsep}}
                  {-0.5cm + (0.5 + sqrt(1.25))*\pgfkeysvalueof{/pgf/outer ysep}}}%
      \pgfpathclose
    \tikz@finish
    \begingroup
      \tikzset{second}%
      \pgfpathmoveto{\pgfqpoint{-0.25cm}{-0.5cm}}%
      \pgfpathlineto{\pgfqpoint{0.25cm}{0.5cm}}%
    \tikz@finish
  }
}
\makeatother
\begin{document}
\begin{tikzpicture}
\matrix[nodes=symbol] {
  \node {};         & \node                      [green] {.}; \\
  \node[dashed] {}; & \node[second/.append style={green}]{.}; \\
};
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

相关内容