装饰路径和箭头

装饰路径和箭头

我用这段代码定义了两个装饰:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\thispagestyle{empty}
\usetikzlibrary{decorations}

\tikzset{%
    pneumatic signal/.style={%
        decoration={%
            pneumatic signal decoration,
            segment length=6pt,
            amplitude=3pt
        },
        very thin,
        decorate
    }
}


\tikzset{%
    system signal/.style={%
        decoration={%
            system signal decoration,
            segment length=10pt,
            amplitude=5pt
        },
        very thin,
        decorate
    }
}


\makeatletter

\pgfdeclaredecoration{pneumatic signal decoration}{line}
{%
    \state{line}[width=+\pgfdecorationsegmentlength,next state=tick,%
            switch if input segment less than=.5\pgfdecorationsegmentlength %
                to segment 1,%
            switch if input segment less than=+\pgfdecorationsegmentlength %
                to segment 2]{%
        \pgfpathlineto{\pgf@x=+\pgfdecorationsegmentlength \pgf@y=0pt}
    }
    \state{tick}[width=1.6\pgfdecorationsegmentamplitude,next state=line,
            switch if input segment less than=1.2\pgfdecorationsegmentamplitude%
                    to segment 2]{%
            \pgfpathlineto{\pgf@x=1.6\pgfdecorationsegmentamplitude \pgf@y=0pt}
            \pgfpathmoveto{\pgf@x=0pt \pgf@y=-.5\pgfdecorationsegmentamplitude}
            \pgfpathlineto{\pgf@x=+\pgfdecorationsegmentamplitude
                \pgf@y=.5\pgfdecorationsegmentamplitude}
            \pgfpathmoveto{\pgf@x=.6\pgfdecorationsegmentamplitude
                \pgf@y=-.5\pgfdecorationsegmentamplitude}
            \pgfpathlineto{\pgf@x=1.6\pgfdecorationsegmentamplitude
                \pgf@y=.5\pgfdecorationsegmentamplitude}
            \pgfpathmoveto{\pgf@x=1.6\pgfdecorationsegmentamplitude \pgf@y=0pt}
    }
    \state{segment 1}[next state=line,%
            width=+\pgfdecoratedinputsegmentremainingdistance]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}
    }
    \state{segment 2}[next state=segment 3,%
            width=+\pgfdecoratedinputsegmentremainingdistance]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}
    }
    \state{segment 3}[next state=tick,%
            width=.2\pgfdecorationsegmentlength,
            switch if input segment less than=.2\pgfdecorationsegmentlength %
                to segment 2]{%
        \pgfpathlineto{\pgf@x=.2\pgfdecorationsegmentlength \pgf@y=0pt}
    }
    \state{final}{%
        \pgfpathlineto{\pgfpointdecoratedpathlast}
    }
}

\pgfdeclaredecoration{system signal decoration}{line}
{%
    \state{line}[width=+\pgfdecorationsegmentlength,next state=symbol,%
            switch if input segment less than=.5\pgfdecorationsegmentlength %
                to segment 1,%
            switch if input segment less than=+\pgfdecorationsegmentlength %
                to segment 2]{%
        \pgfpathlineto{\pgf@x=+\pgfdecorationsegmentlength \pgf@y=0pt}
    }
    \state{symbol}[width=+\pgfdecorationsegmentamplitude,next state=line,
            switch if input segment less than=+\pgfdecorationsegmentamplitude%
                to segment 2]{%
        \pgfpathcircle{\pgf@x=.5\pgfdecorationsegmentamplitude \pgf@y=0pt}
            {.5\pgfdecorationsegmentamplitude}
        \pgfpathcircle{\pgf@x=.5\pgfdecorationsegmentamplitude \pgf@y=0pt}
            {.25\pgfdecorationsegmentamplitude}
        \pgfpathmoveto{\pgf@x=+\pgfdecorationsegmentamplitude \pgf@y=0pt}
    }
    \state{segment 1}[next state=line,%
            width=+\pgfdecoratedinputsegmentremainingdistance]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}
    }
    \state{segment 2}[next state=segment 3,%
            width=+\pgfdecoratedinputsegmentremainingdistance]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}
    }
    \state{segment 3}[next state=symbol,%
            width=.2\pgfdecorationsegmentlength,
            switch if input segment less than=.2\pgfdecorationsegmentlength %
                to segment 2]{%
        \pgfpathlineto{\pgf@x=.2\pgfdecorationsegmentlength \pgf@y=0pt}
    }
    \state{final}{%
        \pgfpathlineto{\pgfpointdecoratedpathlast}
    }
}
\makeatother

\tikz\draw[->,pneumatic signal] (0,0) -- (2,0);
\tikz\draw[->,system signal] (0,0) -- (2,0);

\end{document}

我的问题是,我无法使用“系统信号”装饰绘制以箭头结尾的路径。虽然代码完全相同,但我不明白为什么“气动信号”装饰有效,而“系统信号”装饰无效。我错过了什么?

在此处输入图片描述

编辑:根据要求添加缺失的 MWE 代码(抱歉......)

编辑2:添加了有问题的装饰代码

答案1

问题在于使用\pgfpathcircle,或者更具体地说,这个命令包含一个关闭路径的低级命令。我不得不四处寻找它,但手册(我的 2.10 版本中的第 15.3.4 节)确实指出

如果路径由多段组成,则只有最后一段会获得箭头提示。闭合路径的行为尚未指定,将来可能会发生变化

这可能应该被解释为,不应该期望在包含close-path 任何地方(不仅仅是在最后)。请注意,这还包括用\pgfpathrectangle及其变体绘制的矩形。

但是,至少在这种情况下,一切都没有丢失。由于您无需使用圆形的闭合路径(无论如何,根据我的眼睛),因此您可以只使用圆弧:

\documentclass{standalone}
\usepackage{tikz}

\usetikzlibrary{decorations}

\tikzset{%
    system signal/.style={%
        decoration={%
            system signal decoration,
            segment length=10pt,
            amplitude=5pt
        },
        very thin,
        decorate
    }
}


\pgfdeclaredecoration{system signal decoration}{line}%
{%
    \state{line}[
        width=+\pgfdecorationsegmentlength,next state=symbol,
        switch if input segment less than=.5\pgfdecorationsegmentlength to segment 1,
        switch if input segment less than=+\pgfdecorationsegmentlength to segment 2
    ]{%
        \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{0pt}}%
    }
    %
    \state{symbol}[
        width=+\pgfdecorationsegmentamplitude,
        next state=line,
        switch if input segment less than=+\pgfdecorationsegmentamplitude to segment 2
    ]{%
        \pgfpatharc{180}{-180}{.5\pgfdecorationsegmentamplitude}%
        \pgfpathmoveto{\pgfqpoint{.25\pgfdecorationsegmentamplitude}{0pt}}%
        \pgfpatharc{180}{-180}{.25\pgfdecorationsegmentamplitude}%
        \pgfpathmoveto{\pgfqpoint{\pgfdecorationsegmentamplitude}{0pt}}%
    }%
    %
    \state{segment 1}[%
        next state=line,
        width=+\pgfdecoratedinputsegmentremainingdistance
    ]%
    {%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}%
    }%
    %
    \state{segment 2}[%
        next state=symbol,
        width=+\pgfdecoratedinputsegmentremainingdistance
    ]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}%
    }%
    %
    \state{segment 3}[
        next state=symbol,%
        width=.2\pgfdecorationsegmentlength,
        switch if input segment less than=.2\pgfdecorationsegmentlength to segment 2
    ]{%
        \pgfpathlineto{\pgfqpoint{.2\pgfdecorationsegmentlength}{0pt}}%
    }%
    %
    \state{final}{%
        \pgfpathlineto{\pgfpointdecoratedpathlast}%
    }%
}

\begin{document}

\tikz\draw[->,system signal] (0,0) -- (2,0);

\end{document}

这会产生类似这样的结果:

箭

另外,我们可以破解!此破解添加了一个\ifpgfarrowsonclosedpath和一个关联键(结果与上面相同)。

\documentclass{standalone}
\usepackage{tikz}

\makeatletter

\newif\ifpgfarrowsonclosedpath

\def\pgf@check@for@arrows{%
    \pgf@drawarrowsfalse%
    \ifx\pgf@startarrow\pgfutil@empty\else\pgf@drawarrowstrue\fi%
    \ifx\pgf@endarrow\pgfutil@empty\else\pgf@drawarrowstrue\fi%
    \ifdim\pgf@shorten@end@additional=0pt\relax\else\pgf@drawarrowstrue\fi%
    \ifdim\pgf@shorten@start@additional=0pt\relax\else\pgf@drawarrowstrue\fi%
    \ifpgf@drawarrows%
        \pgfsyssoftpath@getcurrentpath\pgf@arrowpath%
        \ifx\pgf@arrowpath\pgfutil@empty%
            \pgf@drawarrowsfalse%
        \else%
            \ifpgfarrowsonclosedpath%
            \else%
            \pgfprocesscheckclosed{\pgf@arrowpath}{\pgf@drawarrowsfalse}%
            \fi%
        \fi%
    \fi%
}


\tikzset{arrows on closed path/.is if=pgfarrowsonclosedpath}

\usetikzlibrary{decorations}

\tikzset{%
    system signal/.style={%
        decoration={%
            system signal decoration,
            segment length=10pt,
            amplitude=5pt
        },
        very thin,
        arrows on closed path, 
        decorate
    }
}


\pgfdeclaredecoration{system signal decoration}{line}%
{%
    \state{line}[
        width=+\pgfdecorationsegmentlength,next state=symbol,
        switch if input segment less than=.5\pgfdecorationsegmentlength to segment 1,
        switch if input segment less than=+\pgfdecorationsegmentlength to segment 2
    ]{%
        \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{0pt}}%
    }
    %
    \state{symbol}[
        width=+\pgfdecorationsegmentamplitude,
        next state=line,
        switch if input segment less than=+\pgfdecorationsegmentamplitude to segment 2
    ]{%
        \pgfpathcircle{\pgfqpoint{.5\pgfdecorationsegmentamplitude}{0pt}}{.5\pgfdecorationsegmentamplitude}%
        \pgfpathcircle{\pgfqpoint{.5\pgfdecorationsegmentamplitude}{0pt}}{.25\pgfdecorationsegmentamplitude}%
        \pgfpathmoveto{\pgfqpoint{\pgfdecorationsegmentamplitude}{0pt}}%
    }%
    %
    \state{segment 1}[%
        next state=line,
        width=+\pgfdecoratedinputsegmentremainingdistance
    ]%
    {%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}%
    }%
    %
    \state{segment 2}[%
        next state=symbol,
        width=+\pgfdecoratedinputsegmentremainingdistance
    ]{%
        \pgfpathlineto{\pgfpointdecoratedinputsegmentlast}%
    }%
    %
    \state{segment 3}[
        next state=symbol,%
        width=.2\pgfdecorationsegmentlength,
        switch if input segment less than=.2\pgfdecorationsegmentlength to segment 2
    ]{%
        \pgfpathlineto{\pgfqpoint{.2\pgfdecorationsegmentlength}{0pt}}%
    }%
    %
    \state{final}{%
        \pgfpathlineto{\pgfpointdecoratedpathlast}%
    }%
}


\begin{document}

\tikz\draw[->,system signal] (0,0) -- (2,0);

\end{document}

编辑:扩展了未绘制箭头的情况并添加了 hack。

相关内容