Latex TIKZ - 绘制 YAWL 工作流任务

Latex TIKZ - 绘制 YAWL 工作流任务

我想为我的论文创建一个 YAWL 模式。该模式由任务组成,如下图所示,我的最终模型看起来像绘制的图表(它的简化版本)。

YAWL 图案元素

所需的工作流模型

我非常喜欢下图的设计https://texample.net/tikz/examples/model-physics/。我的问题是,我真的不明白如何开始开发我自己的模型(即使经过广泛的研究),同时又被 fe \usetikzlibrary、newcommand、节点中的节点,甚至 tikzspicture 中的 tikzpicture 的可能性所淹没——我不再对潜在的解决方案有一个概述。

  • 如何定义可在整个工作流模型中使用的灵活的 TIKZ 任务定义?
  • 总体而言,是否存在设计此类工作流模型的最佳实践?

我将非常感谢您能提供简短的解释或仅仅是一个可以回答我的问题的链接(我发现的文档和其他教程仅对我的具体情况有有限的帮助)

答案1

任务:

  1. 节点的外观。
  2. 节点的放置。
  3. 连接节点。

1. 节点外观

这是一个原始的 TikZ 方法。

所有这些符号都是circle或形状,通过(将另一个节点放置在与我们使用它的节点相关的位置)和(允许我们用它引用最后放置的节点的名称)rectangle绘制一些额外的东西。labelappend after command\tikzlastnode

  • 在输入和输出条件的情况下,它只是另一个label被填充的形状(a)。
  • 复合任务只是一个double矩形。
  • 多个任务会额外绘制一个边框。(还有copy shadow
  • 拆分任务再次成为rectangle绘制额外内容的节点。

  • add anchor alias to me
  • add anchor to me

仅将自定义锚点添加到该位置rectangle

(在这种split情况下,这只是和和.in的别名。因为它只是反过来而已。).westout 1out 2join

calc库允许我们写入指定部分位于和之间的($(<c1>)!<perc>!(<c2>)$)点。percc1c2

(额外的锚点与 一起使用\pgfpointlineattime。)


可以通过使用来自的形状来改进此解决方案shapes.gates.logic图书馆并删除文本(但仍然添加额外的内容)。

这些形状带有可变数量的输入和输出锚点(也可以反转绘制)。

各种circuits库还提供了更多可能有助于绘制这些图表的键。还有circuitikz包裹(→),但我没有在那里看到任何逻辑门。

2. 节点的放置。

放置节点的方法有几十种。

我在这里使用了\matrix,因为它将所有节点整齐地放在网格上并对其进行命名<matrix name>-<row>-<column>

chains图书馆和图书馆还有其他方法graphs

3.连接节点。

我只是使用了一堆edge操作,ext.paths.ortho我的库tikz-ext包裹帮助几条正交线:

  • horizontal vertical horizontal(= -|-),
  • only horizontal first(这似乎有问题,因为.west必须手动声明),
  • only horizontal second
  • r-du利用辅助坐标绘制环边的操作。

tikzcd包允许人们将节点放置在矩阵中并指定连接,而不必知道节点在矩阵中的位置,这里可以类似地使用节点。

还有更多。

fit和库backgrounds帮助在图表的其他部分后面绘制一个绿色矩形。

代码

\documentclass[border=1pt,tikz]{standalone}
\usetikzlibrary{
    matrix,           % for matrix of nodes
    shapes.geometric, % for isosceles triangle
    calc,             % for $-syntax
    ext.paths.ortho,  % for -|-
    fit,
    backgrounds,
}
\makeatletter
\tikzset{
  add anchor to node/.code n args={3}{%
    \edef\tikz@temp##1{%  \tikz@pp@name/\tikzlastnode needs to be expanded
      \noexpand\pgfutil@g@addto@macro\expandafter\noexpand\csname pgf@sh@ma@\tikz@pp@name{#1}\endcsname{%
        \def\expandafter\noexpand\csname pgf@anchor@\csname pgf@sh@ns@\tikz@pp@name{#1}\endcsname @#2\endcsname{##1}%
      }}\tikz@temp{#3}},
  add anchor to me/.style 2 args={append after command={
    [add anchor to node={\tikzlastnode}{#1}{#2}]}},
  add anchor alias to node/.style n args={3}{
    add anchor to node={#1}{#2}{\pgf@sh@reanchor{\csname pgf@sh@ns@\pgfreferencednodename\endcsname}{#3}}},
  add anchor alias to me/.style args={#1 for #2}{append after command={
      [add anchor alias to node={\tikzlastnode}{#1}{#2}]}}}
\makeatother
\tikzset{
  yawl diagram/.style={
    yawl size/.initial=1cm,
    yawl task part/.initial=.2,
    all yawl/.style={draw, minimum size=\pgfkeysvalueof{/tikz/yawl size}},
    %% Conditions
    condition/.style={all yawl, shape=circle},
    input condition triangle/.style={
      shape=isosceles triangle, fill=black, draw=none,
      xshift=-.1*\pgfkeysvalueof{/tikz/yawl size},
      minimum width=.5*\pgfkeysvalueof{/tikz/yawl size},
      minimum height=.3*\pgfkeysvalueof{/tikz/yawl size}},
    output condition square/.style={
      shape=rectangle, fill=black, draw=none,
      minimum size=.5*\pgfkeysvalueof{/tikz/yawl size}},
    input condition/.style={
      condition, label={[input condition triangle]center:}},
    output condition/.style={
      condition, label={[output condition square]center:}},
    %% Tasks
    atomic task/.style={all yawl, shape=rectangle},
    composite task/.style={
      atomic task, double, double distance=1.5pt,
      outer sep=2\pgflinewidth+\pgfinnerlinewidth},
    multiple path/.style n args=3{
     append after command={
        ([xshift=##1]\tikzlastnode.north west)
        edge[##3, to path={|- ([shift={(##2,##2)}]\tikzlastnode.north east)
                          |- ([yshift=##1]\tikzlastnode.south east)}] ()}},
    multiple atomics/.style={atomic task, multiple path={2pt}{2pt}{}},
    multiple composites/.style={composite task, multiple path={4pt}{2pt}{double, double distance=1.5pt}},
    %% … that was the easy part
    %% Tasks
    task/.style={
      all yawl, minimum width=1.5*\pgfkeysvalueof{/tikz/yawl size}, shape=rectangle},
    task right/.style={
      task, add anchor alias to me=in for west,
      add anchor to me={out 1}{\pgfpointlineattime{.3}{\northeast}{\csname pgf@anchor@rectangle@south east\endcsname}},
      add anchor to me={out 2}{\pgfpointlineattime{.7}{\northeast}{\csname pgf@anchor@rectangle@south east\endcsname}},
      append after command={
        ($(\tikzlastnode.north east)!\pgfkeysvalueof{/tikz/yawl task part}!(\tikzlastnode.north west)$)
        edge coordinate[midway] (@)
        ($(\tikzlastnode.south east)!\pgfkeysvalueof{/tikz/yawl task part}!(\tikzlastnode.south west)$)
        ##1}},
    task left/.style={
      task, add anchor alias to me=out for east,
      add anchor to me={in 1}{\pgfpointlineattime{.7}{\southwest}{\csname pgf@anchor@rectangle@north west\endcsname}},
      add anchor to me={in 2}{\pgfpointlineattime{.3}{\southwest}{\csname pgf@anchor@rectangle@north west\endcsname}},
      append after command={
        ($(\tikzlastnode.north west)!\pgfkeysvalueof{/tikz/yawl task part}!(\tikzlastnode.north east)$)
        edge coordinate[midway] (@)
        ($(\tikzlastnode.south west)!\pgfkeysvalueof{/tikz/yawl task part}!(\tikzlastnode.south east)$)
        ##1}},
    and split/.style={
      task right={(\tikzlastnode.north east) edge[shorten >=\pgflinewidth, shorten <=\pgflinewidth,
         to path={--(@)--(\tikzlastnode.south east)}]()}},
    xor split/.style={
      task right={(\tikzlastnode.north east-|@) edge[shorten >=\pgflinewidth, shorten <=\pgflinewidth,
         to path={--([xshift=-.5\pgflinewidth]\tikzlastnode.east)--(\tikzlastnode.south east-|@)}]()}},
    or split/.style={
      task right={%
        \pgfextra{\let\tln\tikzlastnode}
        ([yshift=-.5\pgflinewidth]$(\tikzlastnode.north east)!.5!(\tikzlastnode.north-|@)$)
        edge[line join=bevel, to path={-- coordinate[at start](@@) (@) -- ([yshift=.5\pgflinewidth]\tln.south-|@@)
                                       -- ([xshift=-.5\pgflinewidth]\tln.east) -- cycle}]()
        \pgfextra{\let\tikzlastnode\tln}}},
    and join/.style={
        task left={(\tikzlastnode.north west) edge[shorten >=\pgflinewidth, shorten <=\pgflinewidth,
           to path={--(@)--(\tikzlastnode.south west)}]()}},
      xor join/.style={
        task left={(\tikzlastnode.north east-|@) edge[shorten >=\pgflinewidth, shorten <=\pgflinewidth,
           to path={--([xshift=.5\pgflinewidth]\tikzlastnode.west)--(\tikzlastnode.south west-|@)}]()}},
      or join/.style={
        task left={%
          \pgfextra{\let\tln\tikzlastnode}
          ([yshift=-.5\pgflinewidth]$(\tikzlastnode.north west)!.5!(\tikzlastnode.north-|@)$)
          edge[line join=bevel, to path={-- coordinate[at start](@@) (@) -- ([yshift=.5\pgflinewidth]\tln.south-|@@)
                                         -- ([xshift=.5\pgflinewidth]\tln.west) -- cycle}]()
          \pgfextra{\let\tikzlastnode\tln}}}}}
\begin{document}
\begin{tikzpicture}[
  yawl diagram,
  %
  add split/.style={
    append after command={(\tikzlastnode.in)    edge[<-] ++(left:10pt)
                          (\tikzlastnode.out 1) edge[->] ++(right:10pt)
                          (\tikzlastnode.out 2) edge[->] ++(right:10pt)}},
  add split'/.style={
    append after command={(\tikzlastnode.in 1) edge[<-] ++(left:10pt)
                          (\tikzlastnode.in 2) edge[<-] ++(left:10pt)
                          (\tikzlastnode.out)  edge[->] ++(right:10pt)}}
]

\matrix [
  matrix of nodes, row sep=2mm, column sep=2mm,
  thick,
  >=latex,
  column 2/.style={anchor=mid west},
  column 4/.style={anchor=mid west}] {
 |[condition]|        & Condition        & |[atomic task]|         & Atomic task \\
 |[input condition]|  & Input condition  & |[composite task]|      & Composite task \\
 |[output condition]| & Output condition & |[multiple atomics]|    & Multiple atomic tasks \\
                      &                  & |[multiple composites]| & Multiple composite tasks \\
 |[and split, add split]| & AND-split & |[and join, add split']| & AND-join \\
 |[xor split, add split]| & XOR-split & |[xor join, add split']| & XOR-join \\
 |[or split,  add split]| & OR-split  & |[or join,  add split']| & OR-join \\
};
\end{tikzpicture}
\begin{tikzpicture}[yawl diagram]
\matrix (m) [
  matrix of nodes,
  row sep=1cm,
  column sep=1cm,
  l/.style={label={[node font=\scriptsize]below:\vphantom{gV}#1}},
  mgnt/.style={fill=magenta!50}
] {
     & & & & |[composite task, l = Automation]| \\
  |[input condition]|
     & |[xor join, l = loop join]|
       & |[task, l = next step]|
         & |[xor split, l = \dots, mgnt]|
           & |[task, l = manual]|
             & |[xor join, mgnt]|
               & |[xor split, l = loop]|
                 & |[condition]| \\
};
\path[->, thick, shorten >=\pgflinewidth]
  (m-2-1)       edge[horizontal vertical horizontal] coordinate[pos=.85] (loop start) (m-2-2.in 1)
  (m-2-2)       edge (m-2-3)
  (m-2-3)       edge (m-2-4)
  (m-2-4.out 2) edge[only horizontal first] (m-2-5.west)
  (m-2-4.out 1) edge[horizontal vertical horizontal] (m-1-5)
  (m-2-5)       edge[only horizontal second] (m-2-6.in 2)
  (m-1-5)       edge[horizontal vertical horizontal] (m-2-6.in 1)
  (m-2-6)       edge (m-2-7)
  (m-2-7.out 1) edge[horizontal vertical horizontal] coordinate[pos=.15] (loop end) (m-2-8)
  (m-2-7.out 2) edge[
    udlr/du distance=2cm,
    to path={--(loop end|-\tikztostart)r-du(loop start|-\tikztotarget)--(\tikztotarget)}] (m-2-2.in 2)
;
\begin{pgfonlayer}{background}
  \node[draw,
     fill=green!33,
     fit=(m-1-5)(m-2-4)(m-2-6),
     inner ysep=.7cm,
     inner xsep=.5cm,
     yshift=-.35cm,
     label={[anchor=south]south:\textsc{Decision}}
]{};
\end{pgfonlayer}
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述 在此处输入图片描述

相关内容