11

I have defined 2 decorations with this code:

\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}

My problem is that I can't draw a path terminated by an arrow with the "system signal" decoration. Although the code is quite the same, I do not understand why the "pneumatic signal" decoration is working and not the "system signal" one. What do I miss?

enter image description here

Edit: add missing MWE code as requested (sorry...)

Edit2: problematic decoration code added

3
  • I added the minimum code required around yours to get a MWE, compiled it, and it worked (I mean, the arrow tip was drawn). You can test it here [Erm.. No, sorry, the pastebin corrupted the code breaking lines at comment chars...]
    – JLDiaz
    Jan 31, 2013 at 11:13
  • Thanks for your help, I've feared that something was missing in my decoration code. I suppose the question could be closed as "too localized"... Jan 31, 2013 at 12:27
  • After check, it appears that I have this problem just for another more complex decoration. Jan 31, 2013 at 12:38

1 Answer 1

12
+300

The problem is the use of \pgfpathcircle, or to be more specific, the fact that this command includes a low level command which closes the path. I had to hunt to find it but the the manual (section 15.3.4 in my 2.10 version) does state that

If the path consists of several segments, only the last segment gets arrow tips. The behavior for paths that are closed is not specified and may change in the future

This should probably be interpreted as meaning that arrows should not be expected to be drawn on a path containing a close-path anywhere (not just at the end). Note this also includes rectangles drawn with \pgfpathrectangle and it's variants.

However, all is not lost, as least in this case. As you can get away without a close-path with the circle (according to my eyes anyway), you can just use arcs:

\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}

Which produces something a bit like this:

arrow

Also, we can hack! This hack adds an \ifpgfarrowsonclosedpath and an associated key (the results are the same as above).

\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}

EDIT: Expanded on when arrows are not drawn and added hack.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .