[Tex/LaTex] TikZ finishes a morphed path with a straight segment

decorationspathstikz-pgf

When, in TikZ, I apply a path morphing decoration (say, "snake") and specify the segment length option, I often finish up with a straight segment at the end of the path, such as

enter image description here

which often is not the desired behavior. It happens in case there is no room for the whole decoration segment at the end of path. If I do not specify the segment length, it's all right, but I want to have some control over the decoration parameters.

Do you know if there is a way to set the segment length softly in such a way that it is modified a bit automatically in order to get rid of these straight segments?

The picture was produced with the following code:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}

\begin{document}
\begin{tikzpicture}
    \draw[decorate, decoration = {snake, segment length = .4cm}] (0,0) -- (2,0);
\end{tikzpicture}
\end{document}

Best Answer

This is a slightly adapted version of my answer to Nicer wavy line with TikZ. This version doesn't insist on drawing a full sine wave, but will be happy with half periods as well (i.e. it can start and end with an upward arch, while the previous version would always start with an upward and end with a downward arch):

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

\pgfdeclaredecoration{complete sines}{initial}
{
    \state{initial}[
        width=+0pt,
        next state=upsine,
        persistent precomputation={\pgfmathsetmacro\matchinglength{
            \pgfdecoratedinputsegmentlength / int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
            \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
        }] {}
    \state{upsine}[width=\pgfdecorationsegmentlength,next state=downsine]{
        \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
        \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
    }
    \state{downsine}[width=\pgfdecorationsegmentlength,next state=upsine]{
        \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
        \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
}
    \state{final}{}
}

\begin{tikzpicture}[
    every path/.style={
        decoration={
            complete sines,
            segment length=1cm,
            amplitude=1cm
        },
        decorate,
        thick
    }]
\draw (0,0) -- (2,0);
\draw [yshift=-1.2cm] (0,0) -- (2.5,0);
\draw [yshift=-2.4cm] (0,0) -- (3,0);
\draw [yshift=-3.6cm] (0,0) -- (3.5,0);
\end{tikzpicture}
\end{document}