Tikz:定义有条件绘制的自定义形状

Tikz:定义有条件绘制的自定义形状

我正在尝试在 Tikz 中创建自定义形状,以便我能够使用节点的选项来确定如何绘制这种形状。

举个例子带对角线填充的矩形节点考虑到这一点,作为第一次尝试,我尝试实现一个myshape具有单个自定义锚点的简单矩形input,该锚点应绘制在其左侧(选项input west)或右侧(选项input east)。 当然,我知道 Tikz 已经为我提供了实现这一点的方法,但这只是为了在创建更复杂的东西之前进行一个简单的实验。

然而,我的mwe下面我的代码(也利用了一些取自示例:D 触发器和移位寄存器) 无法根据提供的选项计算锚点。事实上,它的行为就像未定义选项一样,即形状始终根据\else我的\if...\else...\fi构造的参数进行编译,这导致input锚点始终绘制在下图中矩形的右侧。

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning,}

\makeatletter

\newif\ifpgf@input@west

% Use these with PGF
\def\pgfsetinputwest{\pgf@input@westtrue}%
\def\pgfsetinputeast{\pgf@input@westfalse}%

% Use these with TikZ
\tikzoption{input west}[]{\pgfsetinputwest}
\tikzoption{input east}[]{\pgfsetinputeast}

% Custom shape (myshape)
\pgfdeclareshape{myshape}{
  % The 'minimum width' and 'minimum height' keys, not the content, determine the size
  \savedanchor\northeast{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=0.5\pgf@x
    \pgf@y=0.5\pgf@y
  }
  % This is redundant, but makes some things easier:
  \savedanchor\southwest{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=-0.5\pgf@x
    \pgf@y=-0.5\pgf@y
  }
  % Inherit from rectangle
  \inheritanchorborder[from=rectangle]

  % Define same anchor a normal rectangle has
  \anchor{center}{\pgfpointorigin}
  \anchor{north}{\northeast \pgf@x=0pt}
  \anchor{east}{\northeast \pgf@y=0pt}
  \anchor{south}{\southwest \pgf@x=0pt}
  \anchor{west}{\southwest \pgf@y=0pt}
  \anchor{north east}{\northeast}
  \anchor{north west}{\northeast \pgf@x=-\pgf@x}
  \anchor{south west}{\southwest}
  \anchor{south east}{\southwest \pgf@x=-\pgf@x}
  \anchor{text}{
    \pgfpointorigin
    \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
    \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
    \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
  }

  % Define anchors for input
    \ifpgf@input@west
        \anchor{input}{
            \pgf@process{\northeast}%
            \pgf@x=-1\pgf@x%
            \pgf@y=0pt%
        }
    \else
        \anchor{input}{
            \pgf@process{\northeast}%
            \pgf@x=1\pgf@x%
            \pgf@y=0pt%
        }
    \fi

  % Draw the rectangle box and the port labels
  \backgroundpath{
    % Rectangle box
    \pgfpathrectanglecorners{\southwest}{\northeast}
  }
}


% Key to add font macros to the current font
\tikzset{add font/.code={\expandafter\def\expandafter\tikz@textfont\expandafter{\tikz@textfont#1}}} 

% Define default style for this node
\tikzset{every myshape node/.style={draw,minimum width=0.4cm,minimum 
height=0.4cm,inner sep=1mm,outer sep=0pt,cap=round,add 
font=\sffamily}}

\makeatother


\begin{document}

\begin{frame}{MWE}
\begin{figure}
\centering
\begin{tikzpicture}[auto, node distance=4mm and 4mm]%
    \node (start) at (0,0) {};
    \node [myshape, draw, input west] (myshape_w) [right=of start] {};
    \node [myshape, draw, input east] (myshape_e) [below=of myshape_w] {};
    \draw [-latex] (start.center) -- (myshape_w.input);
    \draw [-latex] (start.center) |- (myshape_e.input);
\end{tikzpicture}
\end{figure}

\end{frame}

\end{document}

mwe 的结果

我不太明白为什么我的mwe会失败,我只知道一旦引入它,它就会开始偏离我的预期\if...\else...\fi,所以我担心我缺乏一些关于这种低级 Tex 编码如何工作的基本知识。如果能为我指明正确的方向,我将不胜感激。

答案1

有两个问题。锚点在您尚未决定它应该是西还是东时进行评估,并且还需\if要让形状“知道”。所以基本上您需要\deferredanchor(参见 pgfmanual v3.1.4 第 1129 页)和\savedmacro(参见第 1128 页)。我还发现更改一个简单的数字比使用 更直观\if

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

\makeatletter

% Use these with TikZ
\def\my@side{1}
\tikzset{input west/.code=\def\my@internal@side{-1}}
\tikzset{input east/.code=\def\my@internal@side{1}}

% Custom shape (myshape)
\pgfdeclareshape{myshape}{
  % The 'minimum width' and 'minimum height' keys, not the content, determine the size
  \savedanchor\northeast{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=0.5\pgf@x
    \pgf@y=0.5\pgf@y
  }
  % This is redundant, but makes some things easier:
  \savedanchor\southwest{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=-0.5\pgf@x
    \pgf@y=-0.5\pgf@y
  }
  % Inherit from rectangle
  \inheritanchorborder[from=rectangle]

  % Define same anchor a normal rectangle has
  \anchor{center}{\pgfpointorigin}
  \anchor{north}{\northeast \pgf@x=0pt}
  \anchor{east}{\northeast \pgf@y=0pt}
  \anchor{south}{\southwest \pgf@x=0pt}
  \anchor{west}{\southwest \pgf@y=0pt}
  \anchor{north east}{\northeast}
  \anchor{north west}{\northeast \pgf@x=-\pgf@x}
  \anchor{south west}{\southwest}
  \anchor{south east}{\southwest \pgf@x=-\pgf@x}
  \anchor{text}{
    \pgfpointorigin
    \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
    \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
    \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
  }
  \savedmacro{\my@side}{\let\my@side\my@internal@side}
  % Define anchors for input
    \deferredanchor{input}{
           \pgf@process{\northeast}%
            \pgf@x=\my@side\pgf@x%
            \pgf@y=0pt%
        }

  % Draw the rectangle box and the port labels
  \backgroundpath{
    % Rectangle box
    \pgfpathrectanglecorners{\southwest}{\northeast}
  }
}


% Key to add font macros to the current font
\tikzset{add font/.code={\expandafter\def\expandafter\tikz@textfont\expandafter{\tikz@textfont#1}}} 

% Define default style for this node
\tikzset{every myshape node/.style={draw,minimum width=0.4cm,minimum 
height=0.4cm,inner sep=1mm,outer sep=0pt,cap=round,add 
font=\sffamily}}

\makeatother


\begin{document}

\begin{frame}{MWE}
\begin{figure}
\centering
\begin{tikzpicture}[auto, node distance=4mm and 4mm,line cap=rect]%
    \coordinate (start) at (0,0);
    \node [input west,myshape, draw] (myshape_w) [right=of start] {};
    \node [input east,myshape, draw] (myshape_e) [below=of myshape_w] {};
    \draw [-latex] (start) -- (myshape_w.input);
    \draw [-latex] (start) |- (myshape_e.input);
\end{tikzpicture}
\end{figure}

\end{frame}

\end{document}

我还想提请您注意一下/.is choice关键点,这使得我们可以让事情变得更加优雅。

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

\makeatletter

% Use these with TikZ
\def\my@side{1}
\tikzset{input/.is choice,
input/west/.code=\def\my@internal@side{-1},
input/east/.code=\def\my@internal@side{1},
input=east}

% Custom shape (myshape)
\pgfdeclareshape{myshape}{
  % The 'minimum width' and 'minimum height' keys, not the content, determine the size
  \savedanchor\northeast{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=0.5\pgf@x
    \pgf@y=0.5\pgf@y
  }
  % This is redundant, but makes some things easier:
  \savedanchor\southwest{%
    \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
    \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
    \pgf@x=-0.5\pgf@x
    \pgf@y=-0.5\pgf@y
  }
  % Inherit from rectangle
  \inheritanchorborder[from=rectangle]

  % Define same anchor a normal rectangle has
  \anchor{center}{\pgfpointorigin}
  \anchor{north}{\northeast \pgf@x=0pt}
  \anchor{east}{\northeast \pgf@y=0pt}
  \anchor{south}{\southwest \pgf@x=0pt}
  \anchor{west}{\southwest \pgf@y=0pt}
  \anchor{north east}{\northeast}
  \anchor{north west}{\northeast \pgf@x=-\pgf@x}
  \anchor{south west}{\southwest}
  \anchor{south east}{\southwest \pgf@x=-\pgf@x}
  \anchor{text}{
    \pgfpointorigin
    \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
    \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
    \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
  }
  \savedmacro{\my@side}{\let\my@side\my@internal@side}
  % Define anchors for input
    \deferredanchor{input}{
           \pgf@process{\northeast}%
            \pgf@x=\my@side\pgf@x%
            \pgf@y=0pt%
        }

  % Draw the rectangle box and the port labels
  \backgroundpath{
    % Rectangle box
    \pgfpathrectanglecorners{\southwest}{\northeast}
  }
}


% Key to add font macros to the current font
\tikzset{add font/.code={\expandafter\def\expandafter\tikz@textfont\expandafter{\tikz@textfont#1}}} 

% Define default style for this node
\tikzset{every myshape node/.style={draw,minimum width=0.4cm,minimum 
height=0.4cm,inner sep=1mm,outer sep=0pt,cap=round,add 
font=\sffamily}}

\makeatother


\begin{document}

\begin{frame}{MWE}
\begin{figure}
\centering
\begin{tikzpicture}[auto, node distance=4mm and 4mm,line cap=rect]%
    \coordinate (start) at (0,0);
    \node [input=west,myshape, draw] (myshape_w) [right=of start] {};
    \node [input=east,myshape, draw] (myshape_e) [below=of myshape_w] {};
    \draw [-latex] (start) -- (myshape_w.input);
    \draw [-latex] (start) |- (myshape_e.input);
\end{tikzpicture}
\end{figure}

\end{frame}

\end{document}

在此处输入图片描述

相关内容