# spiral spring in tikz

I'm aware of the possibility to easily draw linear springs with tikz but what about spiral springs (torsion)? It looks like there is nothing ready and a long journey in pgf is necessary.

I could reproduce the attached picture with tikz except for the spiral that looks not easy to achieve:

Edit 1: new version with the spiral spring.

Edit 2: code for image 2:

% to be compiled with: pdflatex --jobname=profile-f1 profile.tex
\documentclass[12pt]{book}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[frenchstyle,fulloldstylenums,partialup]{kpfonts}
\usepackage{tikz}
\usetikzlibrary{snakes}
\pgfrealjobname{profile}
\begin{document}
\beginpgfgraphicnamed{profile-f1}
\footnotesize
\begin{tikzpicture}[>=latex,scale=1]
\tikzstyle{spring}=[snake=zigzag,thick,line before snake=0.3cm,line after  snake=0.3cm,segment length=6,segment amplitude=5,join=round]%
\begin{scope}[rotate around={-13:(10,0)}]
\draw[smooth,line width=1pt,fill=black!5] plot coordinates {(0,0)(0.0334,-0.0767)(0.1087,-0.1437)(0.2253,-0.2011)(0.3824,-0.2489)(0.5790,-0.2870)(0.8139,-0.3158)(1.0860,-0.3355)(1.3940,-0.3466)(1.7365,-0.3497)(2.1123,-0.3457)(2.5199,-0.3356) (2.9580,-0.3209)(3.4252,-0.3029)(3.9198,-0.2835)(4.4427,-0.2625)(4.9936,-0.2377)(5.5666,-0.2102)(6.1594,-0.1810)(6.7696,-0.1513)(7.3950,-0.1217)(8.0332,-0.0930)(8.6815,-0.0653)(9.3376,-0.0386)(9.9988,-0.0125)};
\draw[smooth,line width=1pt,fill=black!5] plot coordinates {(0,0)(0.0095,0.0831)(0.0624,0.1691)(0.1590,0.2574)(0.2990,0.3467)(0.4824,0.4357)(0.7085,0.5225)(0.9765,0.6050)(1.2855,0.6812)(1.6341,0.7488)(2.0206,0.8055)(2.4433,0.8492)(2.8998,0.8778)(3.3879,0.8897)(3.9049,0.8833)(4.4459,0.8592)(5.0064,0.8210)(5.5876,0.7687)(6.1870,0.7023)(6.8016,0.6219)(7.4286,0.5277)(8.0650,0.4197)(8.7080,0.2980)(9.3544,0.1623)(10.0012,0.0125)};
% limits
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt](3,-1)--(3,0);
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt](1.75,-1)--(1.75,0);
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt,rotate around={13:(3,0)}](-1,0)--(3,0);
% arrows
\draw[line width=0.5pt,<->](1.75,-1)--node[below]{$ec$}(3,-1);
\draw[line width=0.5pt,<-](3,0) +(180:3.5cm) arc (180:193:3.5cm);
\draw(3,0) +(186.5:3.7cm) node{$\alpha$};
% points
\fill(3,0)circle (2pt);
\draw(3,0)+(155:0.6cm) node{$EC$};
\fill(1.75,0) circle (2pt);
\draw(1.75,0)+(155:0.4cm) node{$AC$};
\begin{scope}[xshift=3cm,rotate=103]
\draw [domain=0:25.1327,variable=\t,smooth,samples=75,line width=1pt]plot ({\t r}:{0.0008*\t*\t});
\end{scope}
\draw[rotate around={13:(3,0)},line width=1pt](3,0.5)--node[right]{$k_\alpha$} (3,2);%
\begin{scope}[rotate around={13:(3,0)}]
\clip (2.75,2) rectangle (3.25,2.25);
\foreach \x in {2.5,2.6,...,5} {
\draw[gray,line width=0.2pt](\x,2)--+(55:2);}
\end{scope}%
\draw[line width=1pt,rotate around={13:(3,0)}] (2.75,2) -- (3.25,2);
\draw[fill=white,white] (8.25,0) --+(0:.5) arc (0:360:.5);
\draw[line width=1pt] (8.25,0) --+(120:.5) arc (120:195:.5);
\fill[fill=white] (8,-.25) rectangle (10,.5);
% winglet
\begin{scope}[rotate around={-30:(8.3,0)},xshift=7.9cm,scale=0.35,y=1.5cm]
\draw[smooth,line width=1pt,fill=black!5] plot coordinates {(0,0)(0.0334,-0.0767)(0.1087,-0.1437)(0.2253,-0.2011)(0.3824,-0.2489)(0.5790,-0.2870)(0.8139,-0.3158)(1.0860,-0.3355)(1.3940,-0.3466)(1.7365,-0.3497)(2.1123,-0.3457)(2.5199,-0.3356) (2.9580,-0.3209)(3.4252,-0.3029)(3.9198,-0.2835)(4.4427,-0.2625)(4.9936,-0.2377)(5.5666,-0.2102)(6.1594,-0.1810)(6.7696,-0.1513)(7.3950,-0.1217)(8.0332,-0.0930)(8.6815,-0.0653)(9.3376,-0.0386)(9.9988,-0.0125)};
\draw[smooth,line width=1pt,fill=black!5] plot coordinates {(0.0000,0.0000)(0.0095,0.0831)(0.0624,0.1691)(0.1590,0.2574)(0.2990,0.3467)(0.4824,0.4357)(0.7085,0.5225)(0.9765,0.6050)(1.2855,0.6812)(1.6341,0.7488)(2.0206,0.8055)(2.4433,0.8492)(2.8998,0.8778)(3.3879,0.8897)(3.9049,0.8833)(4.4459,0.8592)(5.0064,0.8210)(5.5876,0.7687)(6.1870,0.7023)(6.8016,0.6219)(7.4286,0.5277)(8.0650,0.4197)(8.7080,0.2980)(9.3544,0.1623)(10.0012,0.0125)};
\end{scope}
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt,rotate around={-30:(8.3,0)}](8.3,0)--(12,0);
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt,rotate around={-30:(8.3,0)}](8.3,0)--(8.3,-1);
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt,rotate around={-30:(8.3,0)}](11.4,0)--(11.4,-1);
\draw[line width=0.5pt,rotate around={-30:(8.3,0)},<->](8.3,-1)--node[below]{$\vphantom{6}\varepsilon c$}(11.4,-1);
\fill(8.3,0)circle (2pt);
\begin{scope}[xshift=8.3cm,rotate=130]
\draw [domain=0:25.1327,variable=\t,smooth,samples=75,line width=1pt]plot ({\t r}:{0.00085*\t*\t});
\end{scope}
\draw(8.3,0)+(90:0.75cm) node{$k_\delta$};
\draw[line width=0.5pt,<-](8.3,0) +(330:3.2cm) arc (330:360:3.2cm);
\draw(8.3,0) +(345:3.4cm) node{$\delta$};
\draw[line width=0.5pt,dashed,dash pattern=on 4pt off 1.5pt](-1,0)--(12,0);
\end{scope}%
\end{tikzpicture}
\endpgfgraphicnamed%
\end{document}

• If you have finished the code you may consider sending it to TeXample so other can learn from it alternatively you may add the full code as a answer to this question but I’d prefer TeXample … – Tobi May 7 '12 at 20:07
• yes, I can post this online but the code is far to be perfect. I'll see what to do very soon. Other users may be able to improve it. – pluton May 7 '12 at 20:40
• I added the code but I do not think it is nice enough to be posted on texample.net/tikz. The profile was calculated with a function and numerically exported to be used within Tikz. – pluton May 7 '12 at 23:40
• For example, for intrado \draw (10,-0.0125) .. controls (240:0.9) and (-90:0.13) .. (0,0); comes pretty close :) – percusse May 8 '12 at 0:12
• yes, I could have tried to find the closest spline in some sense but at some point, I do not think it is very useful. – pluton May 8 '12 at 1:15

You could use the plot path (and polar coordinates):

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw [domain=0:25.1327,variable=\t,smooth,samples=75]
plot ({\t r}: {0.002*\t*\t});
\end{tikzpicture}
\end{document}


• (+1) But it would be great if you could explain the syntax. – cfr Aug 9 '14 at 0:00
• As an alternative, you could use the TikZ Library for Structural Analysis which defines a torsion spring (support type 6). – David Nov 22 '18 at 11:43

Note: to a full tikz-like command scroll to the bottom of the answer. (I'm sorry for the long text, I got excited)

# A command implementation of Caramdir's answer with some definitions explanation.

The Goal: define a command \spiral which makes a spiral from (coordinate) of N revolutions, has R radius and ends in end angle in the below syntax:

\spiral[options](placement)(end angle:N:R)


Using the plot command with polar coordinates one can define a spiral as being a linear function (not necessary to be linear but makes things way easier) between radius and angle: r = f(θ) = B*θ where the domain is the specified end angle plus the number of revolutions (domain=from 0 to "end angle"*180/pi + N*2*pi - the 180/pi is conversion from degrees to radians). Finally, to make it so that the spiral has radius R the function parameter B must be properly defined, since we want r(end of domain) = R than R = B*"end of domain" and therefore B=R/"end of domain". Implementing this to a new command:

\newcommand\spiral{}% Just for safety so \def won't overwrite something
\pgfmathsetmacro{\domain}{pi*#3/180+#4*2*pi}
\draw [#1,
shift={(#2)},
domain=0:\domain,
variable=\t,
smooth,
samples=int(\domain/0.08)] plot ({\t r}: {#5*\t/\domain})
}


The shift key is used to place the spiral on the requested position, and the sampling is defined through the domain so the spiral will always be smooth (the meaning of \domain/0.08 is "take one point each 5 degrees (0.08 rad) of the domain"). To get a ClockWise spiral just define the end radius as a negative value and redefine the start angle accordingly.

The whole code and an example:

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\newcommand\spiral{}% Just for safety so \def won't overwrite something
\pgfmathsetmacro{\domain}{pi*#3/180+#4*2*pi}
\draw [#1,shift={(#2)}, domain=0:\domain,variable=\t,smooth,samples=int(\domain/0.08)] plot ({\t r}: {#5*\t/\domain})
}

\begin{document}
\begin{tikzpicture}
\spiral[red](0,0)(0:6:6);
\spiral[blue](0,0)(0:6:-6);
\spiral[blue](-12,0)(0:6:6);
\spiral[red](12,0)(0:6:-6);
\spiral[blue](-12,0)(90:2:-2.25);
\spiral[red](12,0)(90:2:2.25);
\end{tikzpicture}
\end{document}


# Bonus spiral:

A bit more complete spiral definition would be to dictate start angle, end angle, start radius, end radius, number of revolutions and placement, right? I won't go about explaining the math, it's quite the same as before but the function is now something like r = f(θ) = A + B*(θ-θ_0) and the domain is domain = "start angle":("end angle"+"revolutions"). The syntax will now be:

\bonusspiral[options](placement)(start angle:end angle)(start radius:end radius)[revs]


And the command definition is:

\newcommand\bonusspiral{} % just for safety
\pgfmathsetmacro{\domain}{#4+#7*360}
\pgfmathsetmacro{\growth}{180*(#6-#5)/(pi*(\domain-#3))}
\draw [#1,
shift={(#2)},
domain=#3*pi/180:\domain*pi/180,
variable=\t,
smooth,
samples=int(\domain/5)] plot ({\t r}: {#5+\growth*\t-\growth*#3*pi/180})
}


The same negative radius definition is valid for clockwise spirals though both start and end radius must be negative, also the start and end angles must be defined accordingly as well. Here is an example code and Image result:

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\newcommand\bonusspiral{} % just for safety
\pgfmathsetmacro{\domain}{#4+#7*360}
\pgfmathsetmacro{\growth}{180*(#6-#5)/(pi*(\domain-#3))}
\draw [#1,
shift={(#2)},
domain=#3*pi/180:\domain*pi/180,
variable=\t,
smooth,
samples=int(\domain/5)] plot ({\t r}: {#5+\growth*\t-\growth*#3*pi/180})
}

\begin{document}
\begin{tikzpicture}
\bonusspiral[red](0,0)(60:270)(-1:-5)[2];
\draw (0,0) -- (240:1);
\draw (0,0) -- (-270:5);
\bonusspiral[blue](10,0)(20:60)(2:5)[5];
\draw (10,0) -- +(20:2);
\draw (10,0) -- +(60:5);
\end{tikzpicture}
\end{document}


# The OP's graphic redesigned and with \spiral!

Also used some new tricks to shorten up the code, the wings are still done by the plot coordinate though.

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns}
\tikzset{dashed/.style={dash pattern=on 4pt off 1.5pt,line width=0.5pt},
wing/.style={smooth,line width=1pt,fill=black!5},
point/.style={circle,inner sep=0pt, minimum width=4pt,fill=black}
}

\newcommand\spiral{} % just for safety
\def\spiral[#1](#2)(#3:#4)(#5:#6)[#7]{%
\pgfmathsetmacro{\domain}{#4+#7*360}
\pgfmathsetmacro{\growth}{180*(#6-#5)/(pi*(\domain-#3))}
\draw [#1,
shift={(#2)},
domain=#3*pi/180:\domain*pi/180,
variable=\t,
smooth,
samples=int(\domain/5)] plot ({\t r}: {#5+\growth*\t-\growth*#3*pi/180})
}
(0.0334,-0.0767)
(0.1087,-0.1437)
(0.2253,-0.2011)
(0.3824,-0.2489)
(0.5790,-0.2870)
(0.8139,-0.3158)
(1.0860,-0.3355)
(1.3940,-0.3466)
(1.7365,-0.3497)
(2.1123,-0.3457)
(2.5199,-0.3356)
(2.9580,-0.3209)
(3.4252,-0.3029)
(3.9198,-0.2835)
(4.4427,-0.2625)
(4.9936,-0.2377)
(5.5666,-0.2102)
(6.1594,-0.1810)
(6.7696,-0.1513)
(7.3950,-0.1217)
(8.0332,-0.0930)
(8.6815,-0.0653)
(9.3376,-0.0386)
(9.9988,-0.0125)}
(0.0095,0.0831)
(0.0624,0.1691)
(0.1590,0.2574)
(0.2990,0.3467)
(0.4824,0.4357)
(0.7085,0.5225)
(0.9765,0.6050)
(1.2855,0.6812)
(1.6341,0.7488)
(2.0206,0.8055)
(2.4433,0.8492)
(2.8998,0.8778)
(3.3879,0.8897)
(3.9049,0.8833)
(4.4459,0.8592)
(5.0064,0.8210)
(5.5876,0.7687)
(6.1870,0.7023)
(6.8016,0.6219)
(7.4286,0.5277)
(8.0650,0.4197)
(8.7080,0.2980)
(9.3544,0.1623)
(10.0012,0.0125)}

\begin{document}
\begin{tikzpicture}[>=latex,scale=1,line width=0.5pt]
\begin{scope}[rotate around={-13:(10,0)}]
% points
\node[point] at (3,0) (EC) {};
\node[point] at (1.75,0) (AC) {};
\draw[dashed] (EC) -- +(-90:1)node[coordinate](ec){};
\draw[dashed] (AC) -- +(-90:1)node[coordinate](ec2){};
\node[above left, outer sep=4pt] at (EC) {$EC$};
\node[above left, outer sep=3pt] at (AC) {$AC$};
\spiral[](EC)(0:100)(0:0.5)[2] node[coordinate] (SpringEnd) {};
\draw[fill=white,white] (8.25,0) -- +(0:.5) arc (0:360:.5);
\draw[line width=1pt] (8.25,0) -- +(120:.5) arc (120:195:.5);
\fill[fill=white] (8,-.25) rectangle (10,.5);
% winglet
\begin{scope}[rotate around={-30:(8.3,0)},xshift=7.9cm,scale=0.35,y=1.5cm]
\end{scope}
\node[point] (kdelta) at (8.3,0) {};
\begin{scope}[rotate around={-30:(8.3,0)}]
\draw[dashed] (8.3,0) -- +(0:3.5) node[coordinate] (deltaEnd) {};
\draw[dashed] (8.3,0) -- +(-90:1.2) node[coordinate](epsC){};
\draw[dashed] (11.4,0) -- +(-90:1.2) node[coordinate](epsC2){};
\end{scope}
\draw[<->] (epsC) -- node[below left] {$\varepsilon c$}(epsC2);
\spiral[](kdelta)(0:130)(0:0.52)[2] node[above right] {$k_\delta$};
\draw[dashed](-1,0)--(12,0);
\draw[<-] (deltaEnd) arc [start angle=-30, delta angle=30, radius=3.5cm] node[midway,right]{$\delta$};
\end{scope}%
\draw[<->] (ec) -- node[below]{$ec$}(ec2);
\draw[->] (EC) +(180:3.5cm) arc [start angle=180, delta angle=-13, radius=3.5cm] node[midway,left]{$\alpha$};
\draw[dashed] (EC) -- +(180:4);
\node[yshift=2cm,pattern=north west lines,minimum width=2cm] (Ground) at (SpringEnd) {};
\draw[line width=1pt] (SpringEnd)-- node[right]{$k_\alpha$} (Ground.south);
\draw (Ground.south west) -- (Ground.south east);
\end{tikzpicture}

\end{document}


# Going spiral crazy, a \spiral tikz-like command!!

Reading How can I create new commands in TikZ? I got a little excited and thought of the old (and now deprecated) \bonusspiral. I was not so fond of that fixed syntax, I much prefer the TikZ way, using comma separated lists and default values. So, I implemented the previous line of thought to a command that has very similar TikZ syntax:

\spiral[tikz options]{spiral options} ;


Where the spiral options are:

start radius = <num>, (default is 0)
end radius = <num>, (default is 1)
start angle = <degrees>, (default is 0)
end angle = <degrees>, (default is 0)
name = <text>, (defaul is nameless) % This is useful to have coordinates at start and end of spiral
revolutions = <num>, (default is 2)
center = {<coordinate>}, (default is (0,0)) % Equivalent to shift={<coordinate>}
sample rate = <degrees>, (default is 5) % Means: plot one point each <degrees>
clockwise (default is false) % This is used as boolean, when present spiral is clockwise


So, it is possible to readily define a spiral just saying \spiral{}; and it will follow the default values. To customize it, add the pertinant options. Important: most of the times connecting things is either needed or very helpful, the name option (say name=myspiral), when given, specifies two coordinates: (myspiralend) and (myspiralstart), which as you can guess refer to the start and end position of the spiral! (spirals always start from the inside and end on the outside).

Knwon issues: as you may have noticed, it is not possible to inform units in the keys, so we are tied to the coordinate system units of tikz (default is cm). A workaround for this is to use \begin{scope}[x=1<unit>,y=1<unit>], but you cannot say for instance start radius=1in and end radius=5cm (you'll get crazy results). When using \spiral{clockWise} node {A}; you'll get a node at the spiral's start position and if used node[at start] you'll get a node at the spiral's center (this occurs even for non clockWise).

My last goal, to raise the done flag, was to make a spiral to=<coordinate> option, that when given the spiral would go from its starting position to the specified <coodinate>, following the other given instructions except for the end radius, but it got somewhat complicated :(.

### The \spiral definition (needs only tikz):

\makeatletter
\newif\ifspiral@is@clockwise
\pgfkeys{
spiral/.is family,
spiral,
start angle/.initial=0,
end angle/.initial=0,
revolutions/.initial=2,
name/.initial=,
center/.initial={(0,0)},
sample rate/.initial =5,
clockwise spiral/.is if=spiral@is@clockwise,
clockwise spiral/.default=false,
clockwise/.style={clockwise spiral=true},
default spiral/.style={start angle=0,end angle=0, start radius=0, end radius=1, revolutions=2, name=, center={(0,0)}, sample rate=5, clockwise spiral=false}
}
\newcommand\spiral[2][]{
\pgfkeys{spiral, default spiral,#2,
start angle/.get=\spiral@start@angle,
end angle/.get=\spiral@end@angle,
revolutions/.get=\spiral@revolutions,
name/.get=\spiral@name,
sample rate/.get=\spiral@sample@rate,
center/.get=\spiral@center
}
\def\spiral@start@name{}
\def\spiral@end@name{}
\ifspiral@is@clockwise
\renewcommand*{\spiral@start@angle}{\pgfkeysvalueof{/spiral/end angle}}
\renewcommand*{\spiral@end@angle}{\pgfkeysvalueof{/spiral/start angle}}
\if\relax\detokenize{\spiral@name}\relax
\else
\renewcommand*{\spiral@start@name}{\spiral@name end}
\renewcommand*{\spiral@end@name}{\spiral@name start}
\fi
\else
\if\relax\detokenize{\spiral@name}\relax
\else
\renewcommand*{\spiral@start@name}{\spiral@name start}
\renewcommand*{\spiral@end@name}{\spiral@name end}
\fi
\fi
\pgfmathsetmacro{\spiral@domain}{\spiral@end@angle+\spiral@revolutions*360}
\draw [#1,
shift={\spiral@center},
domain=\spiral@start@angle*pi/180:\spiral@domain*pi/180,
variable=\t,
smooth,
}
\makeatother


### A MWE

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\spiral{center={(3,0)}, name=defaultspiral};
\node[above=0.6cm,align=center] at (defaultspiralstart) {This\\is the\\default spiral!};
\spiral{center={(5,0)}, clockwise, name=clockwisespiral};
\node[below=0.6cm,align=center] at (clockwisespiralstart) {This\\is a\\clockwise spiral!};
\spiral[blue, dashed]{start angle=45, end angle=90, start radius=1, end radius=2, revolutions=4, clockwise, name=sp1} node[at start]{At center};
\spiral[red, shift={(180:3.5)}]{end angle=45, end radius= 1, name=sp2} node[above left]{A custom spiral};
\foreach \sp in {defaultspiral,clockwisespiral,sp1,sp2}{
\fill[red!80!black] (\sp end) circle (1pt);
\fill[green!80!black] (\sp start) circle (1pt);
}
\end{tikzpicture}
\end{document}


Please report if any bugs are found.

• Although an old topic, this is a superb answer! – Dux Oct 12 '16 at 14:32
• Old but not fully developed! Thank's though, hope it helps more people... – Guilherme Zanotelli Oct 12 '16 at 14:35