定义新的 pgfshape 时,如何在 foreach 循环中创建锚点?

定义新的 pgfshape 时,如何在 foreach 循环中创建锚点?

我在 Tikz 中定义了一个通用压力容器形状,其连接端口数量各不相同。我想在“foreach”循环中为每个连接端口定义锚点,但无法使其正常工作。我尝试按照\pgfdeclareshape:如何在循环中定义锚点?,但是不起作用。这是我的代码:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{ifthen}

\usetikzlibrary{positioning}

\makeatletter

\pgfkeys{/tikz/.cd,% to set the path
    width/.initial=1,
    width/.store in = \vesselwidth,
    width/.get = \vesselwidth,
    height/.initial=2,
    height/.store in = \vesselheight,
    height/.get = \vesselheight,
    bottom connection/.initial=false,
    bottom connection/.get = \bconnection,
    bottom connection/.store in = \bconnection,
    top connection/.initial=false,
    top connection/.get = \tconnection,
    top connection/.store in = \tconnection,    
    connection size/.initial=0.15,
    connection size/.store in = \consize,
    connection size/.get = \consize,
    right connections/.initial={},
    right connections/.get = \rconnections,
    right connections/.store in = \rconnections,
    left connections/.initial={},
    left connections/.get = \lconnections,
    left connections/.store in = \lconnections,
}

\tikzset{minimum width= \vesselwidth cm}
\tikzset{minimum height= \vesselheight cm}

\pgfdeclareshape{column3}{

    \inheritsavedanchors[from=rectangle]
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south east}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{north west}
    \anchor{north}{
        \pgf@process{\northeast}
        \pgf@xa=\pgf@x
        \pgf@ya=\pgf@y
        \advance\pgf@x by -\pgf@xa
        \advance\pgf@y by 0.667\pgf@xa
    }
    \anchor{south}{
        \pgf@process{\southwest}
        \pgf@xa=\pgf@x
        \pgf@ya=\pgf@y
        \advance\pgf@x by -\pgf@xa
        \advance\pgf@y by 0.667\pgf@xa
    }

    \backgroundpath{

        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        %  Construct main path
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}

        % Add connections on the left side
        \foreach \i [count=\ii] in \lconnections
        {
            \def\connectionpos{\pgfpartway{\i}{\pgfpoint{\pgf@xa}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{        0 cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{-1.2*\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connection\ii w} {\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 0 cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 1.2*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{        0 cm}{ 0.8*\consize cm}}}
        }
        \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}

        % Add connection to top of vessel
        \pgfmathsetmacro{\angle}{acos(\consize*0.8/(0.5*\vesselwidth)}
        \pgfpatharc{0}{\angle}{\pgf@xa and -0.667\pgf@xa}

        \ifthenelse{\boolean{\tconnection}}
        {
            \def\connectionpos{\pgfpoint{0}{\pgf@yb+0.667*\pgf@xb}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{0}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-1.2*\consize cm}{\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connectiont} {\pgfrelative{\connectionpos}{\pgfpoint{0 cm}{ \consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 1.2*\consize cm}{\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{\consize cm}}}  
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{0}}}    
        }
        {\pgfpatharc{\angle}{180-\angle}{\pgf@xa and -0.667\pgf@xa}}
        \pgfpatharc{180-\angle}{180}{\pgf@xa and -0.667\pgf@xa}

        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}

        % Add connections on the right side
        \foreach \i [count=\ii] in \rconnections
        {
            \def\connectionpos{\pgfpartway{\i}{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xb}{\pgf@ya}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{       0 cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 1.2*\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connection\ii e} {\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 0 cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{-1.2*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{       0 cm}{-0.8*\consize cm}}}
        }
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}

        % Add connection to bottom of vessel
        \pgfmathsetmacro{\angle}{acos(\consize*0.8/(0.5*\vesselwidth)}
        \pgfpatharc{0}{\angle}{-\pgf@xa and 0.667\pgf@xa}

        \ifthenelse{\boolean{\bconnection}}
        {
            \def\connectionpos{\pgfpoint{0}{\pgf@ya+0.667*\pgf@xa}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{0}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{-\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 1.2*\consize cm}{-\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connectionb} {\pgfrelative{\connectionpos}{\pgfpoint{0 cm}{ -\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-1.2*\consize cm}{-\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{-\consize cm}}} 
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{0}}}    
        }
        {\pgfpatharc{\angle}{180-\angle}{-\pgf@xa and 0.667\pgf@xa}}
        \pgfpatharc{180-\angle}{180}{-\pgf@xa and 0.667\pgf@xa}
        \pgfpathclose
    }
}

\makeatother

\begin{document}

    \begin{tikzpicture}[auto, node distance=1.5cm]

    % Draw the first tank 
    \node[column3,draw,thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.10,0.90},
    left connections={0.5}] (col1) {};

    % Draw the second tank  
    \node[column3,draw,right=of col1.connection2e, anchor=connection1w, thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.25,0.90},
    left connections={0.25}] (col2) {};

    \draw[->](col1-connection2e) -- (col2-connection1w);

    \end{tikzpicture}

\end{document}

导致: 期望结果

我想通过在每个连接上定义一个锚点来避免使用 xshift/yshift,这样我就可以这样写:

\begin{document}

    \begin{tikzpicture}[auto, node distance=1.5cm]

    % Draw the first tank 
    \node[column3,draw,thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.10,0.90},
    left connections={0.5}] (col1) {};

    % Draw the second tank  
    \node[column3,draw,right=of col1.connection2e, anchor=connection1w, thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.25,0.90},
    left connections={0.25}] (col2) {};

    \draw[->](col1.connection2e) -- (col2.connection1w);

    \end{tikzpicture}

\end{document}

我该怎么做呢?

答案1

在你的代码中

\foreach \i [count=\ii] in \lconnections

\lconnections不是一个列表。即使你写成这样,它也不是一个列表。

\foreach \i [count=\ii] in {\lconnections}

为了\foreach识别此列表,您必须\lconnections在扩展之前进行扩展\foreach

经典技巧如下

    \edef\pgf@marshal{\noexpand\foreach \noexpand\i [count=\noexpand\ii] in {\lconnections}}
    \pgf@marshal

这里,\noexpand保护\foreach//\i并且\ii将会\edef扩大\lconnections

这是功能代码

\documentclass{standalone}
\usepackage{tikz}
\usepackage{ifthen}

\usetikzlibrary{positioning}

\makeatletter

\pgfkeys{/tikz/.cd,% to set the path
    width/.initial=1,
    width/.store in = \vesselwidth,
    width/.get = \vesselwidth,
    height/.initial=2,
    height/.store in = \vesselheight,
    height/.get = \vesselheight,
    bottom connection/.initial=false,
    bottom connection/.get = \bconnection,
    bottom connection/.store in = \bconnection,
    top connection/.initial=false,
    top connection/.get = \tconnection,
    top connection/.store in = \tconnection,    
    connection size/.initial=0.15,
    connection size/.store in = \consize,
    connection size/.get = \consize,
    right connections/.initial={},
    right connections/.get = \rconnections,
    right connections/.store in = \rconnections,
    left connections/.initial={},
    left connections/.get = \lconnections,
    left connections/.store in = \lconnections,
}

\tikzset{minimum width= \vesselwidth cm}
\tikzset{minimum height= \vesselheight cm}

\pgfdeclareshape{column3}{

    \inheritsavedanchors[from=rectangle]
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{south east}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{north west}
    \anchor{north}{
        \pgf@process{\northeast}
        \pgf@xa=\pgf@x
        \pgf@ya=\pgf@y
        \advance\pgf@x by -\pgf@xa
        \advance\pgf@y by 0.667\pgf@xa
    }
    \anchor{south}{
        \pgf@process{\southwest}
        \pgf@xa=\pgf@x
        \pgf@ya=\pgf@y
        \advance\pgf@x by -\pgf@xa
        \advance\pgf@y by 0.667\pgf@xa
    }

    \backgroundpath{

        \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
        \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y

        %  Construct main path
        \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}

        % Add connections on the left side
        \edef\pgf@marshal{\noexpand\foreach \noexpand\i [count=\noexpand\ii] in {\lconnections}}
        \pgf@marshal
        {
            \def\connectionpos{\pgfpartway{\i}{\pgfpoint{\pgf@xa}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{        0 cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{-1.2*\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connection\ii w} {\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 0 cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 1.2*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-\consize cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{        0 cm}{ 0.8*\consize cm}}}
        }
        \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}

        % Add connection to top of vessel
        \pgfmathsetmacro{\angle}{acos(\consize*0.8/(0.5*\vesselwidth)}
        \pgfpatharc{0}{\angle}{\pgf@xa and -0.667\pgf@xa}

        \ifthenelse{\boolean{\tconnection}}
        {
            \def\connectionpos{\pgfpoint{0}{\pgf@yb+0.667*\pgf@xb}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{0}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-1.2*\consize cm}{\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connectiont} {\pgfrelative{\connectionpos}{\pgfpoint{0 cm}{ \consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 1.2*\consize cm}{\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{\consize cm}}}  
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{0}}}    
        }
        {\pgfpatharc{\angle}{180-\angle}{\pgf@xa and -0.667\pgf@xa}}
        \pgfpatharc{180-\angle}{180}{\pgf@xa and -0.667\pgf@xa}

        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}

        % Add connections on the right side
        \edef\pgf@marshal{\noexpand\foreach \noexpand\i [count=\noexpand\ii] in {\rconnections}}
        \pgf@marshal
        {
            \def\connectionpos{\pgfpartway{\i}{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xb}{\pgf@ya}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{       0 cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 1.2*\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connection\ii e} {\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{ 0 cm}}}
            \message{^^J^^J\tikz@fig@name-connection\ii e^^J^^J}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{-1.2*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{\consize cm}{-0.8*\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{       0 cm}{-0.8*\consize cm}}}
        }
        \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}

        % Add connection to bottom of vessel
        \pgfmathsetmacro{\angle}{acos(\consize*0.8/(0.5*\vesselwidth)}
        \pgfpatharc{0}{\angle}{-\pgf@xa and 0.667\pgf@xa}

        \ifthenelse{\boolean{\bconnection}}
        {
            \def\connectionpos{\pgfpoint{0}{\pgf@ya+0.667*\pgf@xa}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{0}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 0.8*\consize cm}{-\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{ 1.2*\consize cm}{-\consize cm}}}
            \pgfcoordinate{\tikz@fig@name-connectionb} {\pgfrelative{\connectionpos}{\pgfpoint{0 cm}{ -\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-1.2*\consize cm}{-\consize cm}}}
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{-\consize cm}}} 
            \pgfpathlineto{\pgfrelative{\connectionpos}{\pgfpoint{-0.8*\consize cm}{0}}}    
        }
        {\pgfpatharc{\angle}{180-\angle}{-\pgf@xa and 0.667\pgf@xa}}
        \pgfpatharc{180-\angle}{180}{-\pgf@xa and 0.667\pgf@xa}
        \pgfpathclose
    }
}

\makeatother

\begin{document}

    \begin{tikzpicture}[auto, node distance=1.5cm]

    % Draw the first tank 
    \node[column3,draw,thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.10,0.90},
    left connections={0.5}] (col1) {};

    % Draw the second tank  
    \path(2,-1.5)
    node[column3,draw, thick,
    scale=1, width=1, height=2.6, 
    bottom connection=false, 
    top connection=false,
    right connections={0.25,0.90},
    left connections={0.25}] (col2) {};

    \draw[->](col1-connection2e) -- (col2-connection1w);
%
    \end{tikzpicture}

\end{document}

顺便说一句,由于您没有正确定义锚点,因此您不能写right=of col1.connection2enor anchor=connection1w。应使用以下之一来定义锚点:

  • \savedanchor
  • \anchor
  • \deferredanchor
  • \anchorborder

相关内容