我在 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.connection2e
nor anchor=connection1w
。应使用以下之一来定义锚点:
\savedanchor
\anchor
\deferredanchor
\anchorborder