[Tex/LaTex] TikZ: Decorated paths without straight segment

decorationspathstikz-pgf

When a path is decorated in TikZ a straight segment might be added at the end, depending on the length of the path. This is undesirable in some cases, and a resolution for the snake decoration has appeared in this question.

I would like to get an integer or half-integer number of wavelengths in a path for a snake and a coil decoration, with the wavelength calculated automatically so that there is no straight segment at the end. I would also like a switch for each of the endpoints that allows me to choose if the path at that endpoint points in one or the other direction.

Best Answer

Here's an extended version of the complete sines decoration, which can now be controlled using start up/start down and end up/end down.

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{decorations}
\begin{document}

\newif\ifstartcompletesineup
\newif\ifendcompletesineup
\pgfkeys{
    /pgf/decoration/.cd,
    start up/.is if=startcompletesineup,
    start up=true,
    start up/.default=true,
    start down/.style={/pgf/decoration/start up=false},
    end up/.is if=endcompletesineup,
    end up=true,
    end up/.default=true,
    end down/.style={/pgf/decoration/end up=false}
}
\pgfdeclaredecoration{complete sines}{initial}
{
    \state{initial}[
        width=+0pt,
        next state=upsine,
        persistent precomputation={
            \ifstartcompletesineup
                \pgfkeys{/pgf/decoration automaton/next state=upsine}
                \ifendcompletesineup
                    \pgfmathsetmacro\matchinglength{
                        0.5*\pgfdecoratedinputsegmentlength / (ceil(0.5* \pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength) )
                    }
                \else
                    \pgfmathsetmacro\matchinglength{
                        0.5 * \pgfdecoratedinputsegmentlength / (ceil(0.5 * \pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength ) - 0.499)
                    }
                \fi
            \else
                \pgfkeys{/pgf/decoration automaton/next state=downsine}
                \ifendcompletesineup
                    \pgfmathsetmacro\matchinglength{
                        0.5* \pgfdecoratedinputsegmentlength / (ceil(0.5 * \pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength ) - 0.4999)
                    }
                \else
                    \pgfmathsetmacro\matchinglength{
                        0.5 * \pgfdecoratedinputsegmentlength / (ceil(0.5 * \pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength ) )
                    }
                \fi
            \fi
            \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
        }] {}
    \state{downsine}[width=\pgfdecorationsegmentlength,next state=upsine]{
        \pgfpathsine{\pgfpoint{0.5\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
        \pgfpathcosine{\pgfpoint{0.5\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
    }
    \state{upsine}[width=\pgfdecorationsegmentlength,next state=downsine]{
        \pgfpathsine{\pgfpoint{0.5\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
        \pgfpathcosine{\pgfpoint{0.5\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
}
    \state{final}{}
}

\begin{tikzpicture}

\draw [gray!30] (0,-7) grid [step=0.5] (2.5,0);
\node at (1.25cm,0) [align=center,anchor=south] {\texttt{start up}\\\texttt{end up}};
\begin{scope}[
    every path/.style={
        decoration={
            complete sines,
            segment length=0.5cm,
            amplitude=0.5cm,
            mirror,
            start up,
            end up
        },
        decorate,
        thick
    }]
\foreach \length [count=\n] in {1,1.25,...,2.5}
    \draw [yshift=-\n cm + 0.5cm] (0,0) node [anchor=east] {\length cm} -- (\length cm,0);
\end{scope}

\begin{scope}[xshift=3cm]
\draw [gray!30] (0,-7) grid [step=0.5] (2.5,0);
\node at (1.25cm,0) [align=center,anchor=south] {\texttt{start up}\\\texttt{end down}};
\begin{scope}[
    every path/.style={
        decoration={
            complete sines,
            segment length=0.5cm,
            amplitude=0.5cm,
            mirror,
            start up,
            end down
        },
        decorate,
        thick
    }]
\foreach \length [count=\n] in {1,1.25,...,2.5}
    \draw [yshift=-\n cm + 0.5cm] (0,0) -- (\length cm,0);
\end{scope}
\end{scope}

\begin{scope}[xshift=9cm]
\draw [gray!30] (0,-7) grid [step=0.5] (2.5,0);
\node at (1.25cm,0) [align=center,anchor=south] {\texttt{start down}\\\texttt{end up}};
\begin{scope}[
    every path/.style={
        decoration={
            complete sines,
            segment length=0.5cm,
            amplitude=0.5cm,
            mirror,
            start down,
            end up
        },
        decorate,
        thick
    }]
\foreach \length [count=\n] in {1,1.25,...,2.5}
    \draw [yshift=-\n cm + 0.5cm] (0,0) -- (\length cm,0);
\end{scope}
\end{scope}

\begin{scope}[xshift=6cm]
\draw [gray!30] (0,-7) grid [step=0.5] (2.5,0);
\node at (1.25cm,0) [align=center,anchor=south] {\texttt{start down}\\\texttt{end down}};
\begin{scope}[
    every path/.style={
        decoration={
            complete sines,
            segment length=0.5cm,
            amplitude=0.5cm,
            mirror,
            start down,
            end down
        },
        decorate,
        thick
    }]
\foreach \length [count=\n] in {1,1.25,...,2.5}
    \draw [yshift=-\n cm + 0.5cm] (0,0) -- (\length cm,0);
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}