# Draw a longitudinal wave in TikZ

I'm trying to obtain this longitudinal wave with TikZ:

Here's my code

\documentclass{article}
\usepackage{tikz}

\begin{document}

\usetikzlibrary{decorations.pathmorphing}

\begin{tikzpicture}[decoration={coil}]

\draw[decorate, decoration={aspect=0.3, segment length=3mm, amplitude=3mm}] (0,0) --(3,0);
\draw[decorate, decoration={aspect=0.3, segment length=0.5mm, amplitude=3mm}] (3,0) -- (3.5,0);
\draw[decorate, decoration={aspect=0.3, segment length=3mm, amplitude=3mm}] (3.5,0) -- (5,0);

\end{tikzpicture}
\end{document}


but so there are the junctions between one line and the others that interrupt the continuity of the coil. How can improve it?

-

It seems that if there isn't room for a complete loop, the path will be finished with a straight line. By making a slight change in the endpoint for the first path, the result is better. Also, to make the loop continous, and not turn around at the midpoint, you can make the amplitude negative for the second and third path.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}

\begin{tikzpicture}[decoration={coil}]

\draw[decorate, decoration={aspect=0.3, segment length=3mm, amplitude=3mm}] (0,0) --(3.03,0);
\draw[decorate, decoration={aspect=0.3, segment length=0.5mm, amplitude=-3mm}] (3.03,0) -- (3.49,0);
\draw[decorate, decoration={aspect=0.3, segment length=3mm, amplitude=-3mm}] (3.48,0) -- (4.98,0);

\end{tikzpicture}
\end{document}


-
wow! thank you! the solution was simpler than I thought! – Ale Jun 11 '11 at 15:49

Here's an alternative to using decorations which gives you a little more control (though I should say at the outset that I think that the more stylised version from the decoration actually looks neater). I recently found myself wanting to draw a helix and so adapted the code for arcs to allow for a transversal shift as it draws the arc. By varying the shift, I can get a longitudinal wave. The code looks a bit complicated, but it is a very simple adaptation of the code for arcs (and of course it could be hidden away in a package!).

Here's the result first:

If the horrible code were in a package, this is what you would write to get that:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{helix}
\begin{document}
\def\gxhelix{0}
\begin{tikzpicture}
\foreach \sep in {0,10,...,360} {
\pgfmathsetmacro{\rsep}{3*cos(\sep)^2}
\helical[.3*\rsep]{\xhelix}{360}
\draw[blue,helix=.3*\rsep]
(\gxhelix,0,0)
start angle=90,
delta angle=360,
y={(0,1,0)},
x={(0,0,-1)}];
\pgfmathsetmacro{\gxhelix}{\xhelix + \gxhelix}
\global\let\gxhelix=\gxhelix
}
\end{tikzpicture}
\end{document}


The helix key replaces the arc macro with the modified one and sets the shift factor in the helix. So by varying that, we can get the wave-like behaviour. The \helical macro is a shortcut for computing the shift factor so that each cycle starts at the right place from the previous.

The horrible code is the following:

\makeatletter
\pgfutil@tempdima=1cm
\pgfmathsetmacro{\pgf@helix@factor}{\the\pgfutil@tempdima}
\pgfkeys{
/tikz/helix/.default={1},
/tikz/helix/.code={
\let\pgf@arc=\pgf@helix
\pgfmathsetmacro{\pgf@helix@st}{#1*\pgf@helix@factor/360}
}
}

% convert an angle into a helical distance
\newcommand{\helical}[3][1]{%
\pgfmathsetmacro{#2}{#1*(#3)/360}%
}

\newdimen\pgf@helix@len
\def\pgf@helix{%
{%
%
\pgf@xa=\pgf@arc@local@angle@a\relax%
\pgf@xb=\pgf@arc@local@angle@b\relax%
\ifdim\pgf@xb<0pt\relax%
\pgf@xb=-\pgf@xb\relax%
\fi%
\ifdim\pgf@xb=90.0pt%
\def\pgfmathresult{0.55228475}%
\else%
\pgfmathparse{1.333333333*tan(.25*\pgf@sys@tonumber{\pgf@xb})}% many thanks to Ken Starks
\fi%
\pgf@helix@len=\pgf@helix@st\pgf@xb\relax
\pgfutil@tempdima=\pgfmathresult\pgfutil@tempdima%
\pgfutil@tempdimb=\pgfmathresult\pgfutil@tempdimb%
%.. controls +(\pgf@xa+90:\pgfutil@tempdima) and +(\pgf@xb-90:\pgfutil@tempdima) .. +(-(#1:#3)+(#2:#3))%
% store first support vector in xa/ya:
\pgf@xa=\pgf@arc@local@angle@a\relax%
\ifdim\pgf@arc@local@angle@b>\pgf@arc@local@angle@a\relax%
\else%
\fi%
\edef\pgf@arc@angle{\pgf@sys@tonumber{\pgf@xa}}%
\pgfpointtransformed{\pgfpointpolar{\pgf@arc@angle}{\pgfutil@tempdima and \pgfutil@tempdimb}}%
\pgf@xa=\pgf@path@lastx%
\pgf@ya=\pgf@path@lasty%
% store target in xb/yb:
\pgf@xb=\pgf@path@lastx%
\pgf@yb=\pgf@path@lasty%
% store second support xc/yc:
\ifdim\pgf@arc@local@angle@b>\pgf@arc@local@angle@a\relax%
\else%
\fi%
\pgfpointtransformed{\pgfpointpolar{\pgf@sys@tonumber{\pgf@arc@local@angle@b}}{\pgfutil@tempdima and \pgfutil@tempdimb}}%
\pgf@xc=\pgf@xb\relax%
\pgf@yc=\pgf@yb\relax%
\advance \pgf@xc by \pgf@x\relax%
\advance \pgf@yc by \pgf@y\relax%