6

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:

the desired nonlinear spring symbol

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}

output of minimal working example code

0

1 Answer 1

8

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.

enter image description here

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}
    \pgftransformationadjustments

    \edef\raven@coils{\number\numexpr\ctikzvalof{bipoles/ravenspring/coils}*2+1}
    \pgfmathsetlength{\pgf@circ@res@step}
    {(\ctikzvalof{bipoles/ravenspring/width}*\pgf@circ@Rlen+\pgfhorizontaltransformationadjustment*.5*\pgflinewidth)/(\raven@coils-1)/2}

    \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left-\pgfhorizontaltransformationadjustment*0.5*\pgflinewidth}{\pgf@circ@res@zero}}
    \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
      {%
        \advance\pgf@circ@res@other by
        \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}

Old answer, setting factors manually:

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

enter image description here

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}
    \pgftransformationadjustments

    \pgfmathsetlength{\pgf@circ@res@step}
    {(\ctikzvalof{bipoles/ravenspring/width}*\pgf@circ@Rlen+\pgfhorizontaltransformationadjustment*.5*\pgflinewidth)/16}

    \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left-\pgfhorizontaltransformationadjustment*0.5*\pgflinewidth}{\pgf@circ@res@zero}}
    \pgfsetcornersarced{\pgfpoint{.5\pgf@circ@res@up}{.5\pgf@circ@res@up}}
    \pgf@circ@res@other = \pgf@circ@res@left
    \advance\pgf@circ@res@other by 0.50\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
    \advance\pgf@circ@res@other by 1.25\pgf@circ@res@step 
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
    \advance\pgf@circ@res@other by 1.50\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
    \advance\pgf@circ@res@other by 1.75\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
    \advance\pgf@circ@res@other by 2.00\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
    \advance\pgf@circ@res@other by 2.25\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
    \advance\pgf@circ@res@other by 2.50\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@up}}
    \advance\pgf@circ@res@other by 2.75\pgf@circ@res@step
    \pgfpathlineto{\pgfpoint{\pgf@circ@res@other}{\pgf@circ@res@down}}
    \advance\pgf@circ@res@other by 1.50\pgf@circ@res@step
    \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:

enter image description here

<factor>s:

0.500
1.250
1.500
1.750
2.000
2.250
2.500
2.750
1.500

More distorted:

enter image description here

<factor>s:

0.250
0.875
1.250
1.625
2.000
2.375
2.750
3.125
1.750

Less distorted:

enter image description here

<factor>s:

0.750
1.625
1.750
1.875
2.000
2.125
2.250
2.375
1.250

Broken:

enter image description here

<factor>s:

0.000
0.500
1.000
1.500
2.000
2.500
3.000
3.500
2.000
1
  • 2
    Impressive positively. My true compliments.
    – Sebastiano
    Commented Jan 31, 2019 at 22:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .