# How can I draw a nonlinear spring in the style of Circuitikz for a mechanical schematic?

The circuitikz package provides an easy way to draw linear springs (springs that have constant stiffness) in a mechanical circuit. I would like to draw a nonlinear spring (its stiffness varies as it stretches) in a circuitikz-like manner, but circuitikz does not provide a symbol for a nonlinear spring. How can I do this?

## Desired output

I would like the symbol to look like a spring with unevenly spaced coils:

## Minimal working example

This code will generate a linear spring symbol.

\documentclass{standalone}
\usepackage{circuitikz}
\begin{document}
\begin{circuitikz}
\draw (0,0) to [spring] (0, 2);
\end{circuitikz}
\end{document}


I made a less clumsy version, in which you can use a key factor to set how off the spring is of the center and, in the process, I ended up making things easy to change the number of coils in the spring, so I added a coils key to change that as well. The default value for factor is 0, so that the behaviour is the same of the original spring, and the default for coils is 4, the same as the original.

Now you can use it with:

\draw (0,0) to [ravenspring={factor=2,coils=4}] (0, 2);


without changing any definition.

The old answer is down below, for reference.

Code:

\documentclass{standalone}
\usepackage{circuitikz}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new:Npn \__raven_factor:nnnn #1 #2 #3 #4
{ \fp_eval:n { #2 + #1*(#3 - (#2))/#4 } }
\cs_new:Npn \__raven_factor_half:nnnn #1 #2 #3 #4
{ \fp_eval:n { 0.5 * ( #2 + #1*(#3 - #2)/#4 ) } }
\cs_set_eq:NN \FullFactor \__raven_factor:nnnn
\cs_set_eq:NN \HalfFactor \__raven_factor_half:nnnn
\cs_set_eq:NN \IntStepVariable \int_step_variable:nnNn
\ExplSyntaxOff

\makeatletter
\ctikzset{bipoles/ravenspring/height/.initial=.5}
\ctikzset{bipoles/ravenspring/width/.initial=.5}
\ctikzset{bipoles/ravenspring/factor/.initial=0}
\ctikzset{bipoles/ravenspring/coils/.initial=4}
\def\pgf@circ@ravenspring@path#1{\pgf@circ@bipole@path{ravenspring}{#1}}
\compattikzset{%
ravenspring/.code = {%
\ctikzset{\circuitikzbasekey,/tikz/to path=\pgf@circ@ravenspring@path}%
\ctikzset{\circuitikzbasekey/bipoles/ravenspring/.cd,#1}
}
}

\pgfcircdeclarebipole{}
{\ctikzvalof{bipoles/ravenspring/height}}
{ravenspring}
{\ctikzvalof{bipoles/ravenspring/height}}
{\ctikzvalof{bipoles/ravenspring/width}}
{%
\pgfsetlinewidth{\pgfkeysvalueof{/tikz/circuitikz/bipoles/thickness}\pgfstartlinewidth}

\edef\raven@coils{\number\numexpr\ctikzvalof{bipoles/ravenspring/coils}*2+1}
\pgfmathsetlength{\pgf@circ@res@step}

\pgfsetcornersarced{\pgfpoint{.5\pgf@circ@res@up}{.5\pgf@circ@res@up}}
\pgf@circ@res@other = \pgf@circ@res@left
\edef\raven@factor{\ctikzvalof{bipoles/ravenspring/factor}}
\IntStepVariable {1} {\raven@coils} \raven@coil
{%
\ifnum
\ifnum\raven@coil=1\space 1\else 0\fi
\ifnum\raven@coil=\raven@coils\space 1\else 0\fi
=0
\expandafter\FullFactor
\else
\expandafter\HalfFactor
\fi
{\raven@coil}{2-\raven@factor}{2+\raven@factor}{\raven@coils}\pgf@circ@res@step
\ifnum \raven@coil=\raven@coils
\let\raven@moveto\pgf@circ@res@zero
\else
\ifodd\raven@coil
\let\raven@moveto\pgf@circ@res@up
\else
\let\raven@moveto\pgf@circ@res@down
\fi
\fi
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\raven@moveto}}
}
\pgfsetbuttcap
\pgfsetbeveljoin
\pgfusepath{stroke}
}
\makeatother

\begin{document}
\begin{circuitikz}
\draw (0,0) to [ravenspring={factor=2,coils=4}] (0, 2);
\end{circuitikz}
\begin{circuitikz}
\draw (0,0) to [ravenspring={factor=3,coils=6}] (0, 2);
\end{circuitikz}
\end{document}


I declared a new shape, ravenspring (if you want to rename it just change all occurrences of ravespring to whatever name you prefer):

To change the ratio between each loop of the spring you have to change the <factor> in:

\advance\pgf@circ@res@other by <factor>\pgf@circ@res@step


so that the sum of the factors is 16. If you don't get the sum to be 16, then the spring will be shorter or longer than the gap available. Furthermore, the first and last factors should be halved, otherwise the last half coil of the spring will be too long.

Full code:

\documentclass{standalone}
\usepackage{circuitikz}

\makeatletter
\ctikzset{bipoles/ravenspring/height/.initial=.5}
\ctikzset{bipoles/ravenspring/width/.initial=.5}
\def\pgf@circ@ravenspring@path#1{\pgf@circ@bipole@path{ravenspring}{#1}}
\compattikzset{ravenspring/.style = {\circuitikzbasekey, /tikz/to path=\pgf@circ@ravenspring@path, l=#1}}
\pgfcircdeclarebipole{}
{\ctikzvalof{bipoles/ravenspring/height}}
{ravenspring}
{\ctikzvalof{bipoles/ravenspring/height}}
{\ctikzvalof{bipoles/ravenspring/width}}
{%
\pgfsetlinewidth{\pgfkeysvalueof{/tikz/circuitikz/bipoles/thickness}\pgfstartlinewidth}

\pgfmathsetlength{\pgf@circ@res@step}

\pgfsetcornersarced{\pgfpoint{.5\pgf@circ@res@up}{.5\pgf@circ@res@up}}
\pgf@circ@res@other = \pgf@circ@res@left
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
\pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@zero}}
\pgfsetbuttcap
\pgfsetbeveljoin
\pgfusepath{stroke}
}
\makeatother

\begin{document}
\begin{circuitikz}
\draw (0,0) to [ravenspring] (0, 2);
\end{circuitikz}
\end{document}


A few variants, changing the unevenness of the spring:

The one above:

<factor>s:

0.500
1.250
1.500
1.750
2.000
2.250
2.500
2.750
1.500


More distorted:

<factor>s:

0.250
0.875
1.250
1.625
2.000
2.375
2.750
3.125
1.750


Less distorted:

<factor>s:

0.750
1.625
1.750
1.875
2.000
2.125
2.250
2.375
1.250


Broken:

<factor>s:

0.000
0.500
1.000
1.500
2.000
2.500
3.000
3.500
2.000

• Impressive positively. My true compliments. – Sebastiano Jan 31 at 22:02