# Custom decoration along curved paths

The problem that I started out with were those straight lines at the end of paths decorated with snake or coil, which I wanted to get rid of. I found a very nice solution here for the wavy line: https://tex.stackexchange.com/a/29645/36900

The problem that I am facing now, however, is when I apply this decoration to curved paths:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\usetikzlibrary{decorations.markings}

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

\begin{document}

\begin{tikzpicture}[line width=1. pt]

\draw[decorate, decoration={snake}]
(3,-3) arc (180:-90:1);
\draw[line width=0.3pt]
(3,-3) arc (180:-90:1);

\draw[decorate,decoration={complete sines}]
(4,1) arc (180:-90:1);
\draw[line width=0.3pt]
(4,1) arc (180:-90:1);

\end{tikzpicture}

\end{document}


One clearly sees how these "decoration segments" are simply rotated and put behind one another resulting in a finite displacement with respect to the initial path, due the finite width of the pattern that is repeated.

I was wondering if there is the possibility to decorate a path "continuously". If I could specify the xy-displacement (x showing tangential to the initial path) of each point along the initial path like this

{0.}{\amplitude * sin(2*pi/\wavelength * \x)}


where \wavelength could be computed at the beginning as in the example above, and \x denotes the actual position along the initial path.

Superimposing an oscillation along the y-coordinate should also allow me to produce coils.

I guess one could define a decoration with segments of width 1pt but I thought that there must be a simpler solution.

• I think How to draw a sine wave on a circular path will help you. – Qrrbrbirlbel Sep 20 '13 at 13:31
• thanks for the reference. However, I don't see how I could apply this solution to an arbitrary curved path. The circle is easily parametrized analytically, so I get a functional form for the x and y coordinate depending on the domain-variable. For a general path I don't have such a parametrization... this is why I think a general solution would require the usage of path decorations. – nobody2100 Sep 20 '13 at 14:12

Not sure it's exactly what is required and it certainly has the risk of being quite slow. But the approach taken here is to essentially plot the sine function along the path.

There is a high possibility of some inaccuracies/ugliness at the very end of the path, due to the low accuracy of TeX. Some ugliness will also occur along paths with acute angles.

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations}

\tikzset{/pgf/decoration/.cd,
number of sines/.initial=10,
angle step/.initial=20,
}
\newdimen\tmpdimen
\pgfdeclaredecoration{complete sines}{initial}
{
\state{initial}[
width=+0pt,
next state=move,
persistent precomputation={
\pgfmathparse{\pgfkeysvalueof{/pgf/decoration/angle step}}%
\let\anglestep=\pgfmathresult%
\let\currentangle=\pgfmathresult%
\pgfmathsetlengthmacro{\pointsperanglestep}%
{(\pgfdecoratedremainingdistance/\pgfkeysvalueof{/pgf/decoration/number of sines})/360*\anglestep}%
}] {}
\state{move}[width=+\pointsperanglestep, next state=draw]{
\pgfpathmoveto{\pgfpointorigin}
}
\state{draw}[width=+\pointsperanglestep, switch if less than=1.25*\pointsperanglestep to final, % <- bit of a hack
persistent postcomputation={
\pgfmathparse{mod(\currentangle+\anglestep, 360)}%
\let\currentangle=\pgfmathresult%
}]{%
\pgfmathsin{+\currentangle}%
\tmpdimen=\pgfdecorationsegmentamplitude%
\tmpdimen=\pgfmathresult\tmpdimen%
\divide\tmpdimen by2\relax%
\pgfpathlineto{\pgfqpoint{0pt}{\tmpdimen}}%
}
\state{final}{
\ifdim\pgfdecoratedremainingdistance>0pt\relax
\pgfpathlineto{\pgfpointdecoratedpathlast}
\fi
}
}

\begin{document}

\begin{tikzpicture}[
sines/.style={
very thick,
line join=round,
draw=black,
decorate,
decoration={complete sines, number of sines=15, amplitude=5pt}
}
]

\draw [red, postaction={sines}]
(0,0) .. controls +(-1,1) and +(1,-1) .. (2,2);

\draw [red, postaction={sines}]