使用 pgfdeclareshape 创建 fifo 符号

使用 pgfdeclareshape 创建 fifo 符号

我正在编译:

  • pdfTeX,版本 3.1415926-2.3-1.40.12(MiKTeX 2.9 64 位)(预加载格式=pdflatex 2011.7.8)
  • pgf 2008/01/15 v2.10 (rcs-修订版 1.12)
  • tikz 2010/10/13 v2.10 (rcs-修订版 1.76)

我正在尝试创建两个新形状,用于 PGF/TikZ 环境,用于嵌入式工程的最终论文。这些符号的目的是制作一个任务图,有点像 UML 图。第一个符号是一个简单的 FIFO 队列符号,我认为它可以作为第二个符号的模板。简单 FIFO 队列符号 带有信号量的 FIFO 队列

这些是我以前上过的嵌入式编程课程中的图。所以我可以自由地创建自己的图。但这些似乎是我学校的标准,所以我不想偏离太多。

通过阅读这个答案我已经明白了(使用 TikZ 绘制 3D 立方体的最简单方法是什么?并感谢 Matthew Leingang 的回答)我可以复制矩形并删除西边和东边,如下所示:

\makeatletter
\pgfkeys{/pgf/.cd,
  fifo offset x/.initial=20pt,
  fifo offset y/.initial=20pt
}

\pgfdeclareshape{fifo}
{
    \inheritsavedanchors[from=rectangle] % this is nearly a rectangle
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}
  \backgroundpath{
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/fifo offset x}}%
    \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/fifo offset y}}%
    \def\ppd@offset{\pgfpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}%
    \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
    \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}%
    \pgfpathclose%
    \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}%
    \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}%
    \pgfpathclose
  }
}
\makeatother

这给了我这个:

无边长方形

我可以接受这一点,将文本放在中心还可以为指向其他节点的箭头打开更多连接点。但我仍然需要一个带有信号量符号和信号量名称的 FIFO。就我而言,我无法破解这一点。我在想我应该做一个多部分节点,这样我就会有一个用于队列名称和信号量名称的字段。

我尝试创建内部垂直线,但只创建了第一条,然后接下来的几条导致编译崩溃。我首先定义它们之间的偏移量:

通过增加:

\pgfkeys{/pgf/.cd,
internal_displacement x/.initial=5pt,
internal_displacement y/.initial=5pt
} 

在第一个 \pgfkeys 和 \pgfdeclareshape 之间,然后我使用以下命令为垂直线定义了新的 x 轴值:

\pgf@xc=\pgf@xb \advance\pgf@xc by-\pgfkeysvalueof{/pgf/internal_displacement x}%

并添加路径:

\pgfpathmoveto{\pgfqpoint{\pgf@xc}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@yb}}
\pgfpathclose

这给了我这个:

具有一条垂直线的 FIFO

太棒了!对吧?!但是我想定义更多的垂直线,所以我在声明 \pgf@xc 之后立即添加了这个:

\pgf@xd=\pgf@xc \advance\pgf@xd by-\pgfkeysvalueof{/pgf/internal_displacement x}%
\pgf@xe=\pgf@xd \advance\pgf@xe by-\pgfkeysvalueof{/pgf/internal_displacement x}%
\pgf@xf=\pgf@xe \advance\pgf@xf by-\pgfkeysvalueof{/pgf/internal_displacement x}%

我认为这应该将 x 值向左移动 internal_displacement x,但是我却得到了一大堆错误,如下所示:

\pgf@sh@bg@fifo ...nternal_displacement x}\pgf@xe 
                                              =\pgf@xd \advance \pgf@xe ...
l.10 ...idth=2cm,align=center] (fifo1)  {Node One};

我猜想 internal_displacement x 在第一次读取后就被清除了?这似乎适得其反。一定还有其他方法可以做到这一点。

那么有谁知道:

  1. 获取使用多部分节点添加的信号量符号(因此我必须使用文本字段)
  2. 我在垂直线上做错了什么?我在想,如果我能解决这个问题,我就不会在垂直线和水平线之间的距离上遇到麻烦了。

答案1

如果形状声明变得困难,您还可以用图案填充来放置节点并对其进行装饰。

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns}
\makeatletter
\tikzset{
    mynode/.style={outer sep=1mm,
    pattern=vertical lines,
    minimum width=2cm,
    minimum height=1cm,
    append after command={
        \pgfextra{
        \draw(\tikzlastnode.north east) -- (\tikz@last@[email protected] west);
        \draw(\tikz@last@[email protected] east) -- (\tikz@last@[email protected] west);
        \node[anchor=north] at (\tikz@last@[email protected]) {#1};}
        }
    },
    with flag/.style={append after command={
        \pgfextra{
        \draw[fill=white](\tikzlastnode.135) circle (3mm);
        \draw[fill,line width=1mm,line cap=round,line join=round]
        ([xshift=-1pt]\tikzlastnode.135) +(0,-2mm) -- ++(0,2mm) --++(-35:2mm) --++(-145:2mm);
        }
        },
    }
}
\makeatother


\begin{document}

\begin{tikzpicture}
\node[mynode={Queue Name}] (a) at (0,0) {};
\node[mynode={Another Queue}, with flag] (b) at (1,2) {};
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案2

以下是一些入门知识。首先,基本要点:

  1. 错误消息是由于您尝试使用尚未初始化的维度寄存器而产生的。这些是\pgf@xd和 等等。仅最多\pgf@xc\pgf@yc已被声明。除非您正在做一些非常棘手的事情,否则通常可以简单地重用已经存在的寄存器。不过,这可能需要一点簿记。

  2. 要重复某些内容,请使用循环。节点旨在根据文本调整大小,因此指定固定数量的条形会带来麻烦。更好的方法是使用循环绘制条形,并在到达底部之前停止。

这里有一些可以实现该功能的代码,以及将绘图移到文本上方。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/71487/86}
\usepackage{tikz}

\makeatletter
\pgfkeys{/pgf/.cd,
  fifo offset x/.initial=20pt,
  fifo offset y/.initial=20pt,
  internal_displacement x/.initial=5pt,
  internal_displacement y/.initial=5pt,
  fifo height/.initial=20pt,
} 
\pgfdeclareshape{fifo}
{
    \inheritsavedanchors[from=rectangle] % this is nearly a rectangle
    \inheritanchorborder[from=rectangle]
    \inheritanchor[from=rectangle]{north}
    \inheritanchor[from=rectangle]{north west}
    \inheritanchor[from=rectangle]{north east}
    \inheritanchor[from=rectangle]{center}
    \inheritanchor[from=rectangle]{west}
    \inheritanchor[from=rectangle]{east}
    \inheritanchor[from=rectangle]{mid}
    \inheritanchor[from=rectangle]{mid west}
    \inheritanchor[from=rectangle]{mid east}
    \inheritanchor[from=rectangle]{base}
    \inheritanchor[from=rectangle]{base west}
    \inheritanchor[from=rectangle]{base east}
    \inheritanchor[from=rectangle]{south}
    \inheritanchor[from=rectangle]{south west}
    \inheritanchor[from=rectangle]{south east}
  \backgroundpath{
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x
    \northeast \pgf@xb=\pgf@x \pgf@ya=\pgf@y
    \pgf@yb=\pgf@ya
    \advance\pgf@yb by \pgfkeysvalueof{/pgf/fifo height}%
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/fifo offset x}}%
    \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/fifo offset y}}%
    \def\ppd@offset{\pgfpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}%
    \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
    \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}%
    \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}%
    \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}%
    \pgf@xc=\pgf@xb
    \advance\pgf@xc by-\pgfkeysvalueof{/pgf/internal_displacement x}%
    \advance\pgf@xa by \pgfkeysvalueof{/pgf/internal_displacement x}%
    \advance\pgf@yb by-\pgfkeysvalueof{/pgf/internal_displacement y}%
    \advance\pgf@ya by \pgfkeysvalueof{/pgf/internal_displacement y}%
    \loop\ifdim\pgf@xc>\pgf@xa\relax
\pgfpathmoveto{\pgfqpoint{\pgf@xc}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xc}{\pgf@yb}}
\advance\pgf@xc by-\pgfkeysvalueof{/pgf/internal_displacement x}%
    \repeat
\pgfpathclose
  }
}
\makeatother

\begin{document}
\begin{tikzpicture}
\node[fifo,draw] {Node One};
\end{tikzpicture}
\end{document}

结果:

队列形状

进一步的工作:

  1. 边界框计算错误,我认为是因为背景路径没有围绕文本。只需使用一个简单的 即可修复此问题\pgfpathmoveto
  2. 锚点应该调整,真的north east位于整个图表的东北部,而不是文本的东北部。(请注意已保存锚点锚点用于坐标计算。)
  3. 您可能需要使用更多锚点来指向不同的部分:文本和绘图。
  4. 对于信号量,我同意多部分节点是可行的方法。

相关内容