39

If I draw a coil in tikz I usually do something like this:

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.pathmorphing,patterns}

\begin{document}

\begin{tikzpicture}
\draw[decoration={aspect=0.3, segment length=3.2mm, amplitude=3mm,coil},decorate,opacity=0.9] (1,0) -- (3,0);
\end{tikzpicture}
\end{document}

Which looks like this:

enter image description here

In some cases (for example in eletrodynamics) it might matter if the coil is right or left handed.

How can I modify the code above such that it looks like this:

enter image description here

If you have another, maybe better way to visualize the direction I am interested in it too.

5
  • 1
    The image quality of your second image is not very good. Can you clarify which aspect of it you'd like to replicate in your own image? There seem to be a change in line colour/line width as well as a small gap where the wire overlaps, but it is hard to see clearly in this pixelated image. Sep 6, 2018 at 12:43
  • It only matters in a schematic for transformers. One typically adds a dot toward one end of the coil to indicate polarity. Sep 6, 2018 at 12:52
  • @samcarter I want the line with change and the little gap.
    – Julia
    Sep 6, 2018 at 13:27
  • Are you trying to draw DNAs by the way? :-)
    – hola
    Jan 22, 2019 at 11:25
  • No, its about coils in EM-circuits for induction experiments.
    – Julia
    Feb 5, 2019 at 6:37

2 Answers 2

68

The starting point of all this is the code in pgflibrarydecorations.pathmorphing.code.tex. I acknowledge a comment by joojaa that pointed out that the halo was not quite right in the original answers. I also appreciate a comment by Robert Harvey, who encouraged me to clean up. What I did is to modify the coil decoration of the decorations.pathmorphing library. There is still a lot of room for improvement. The keys in the beginning allow you to adjust the color, opacity, width of coil and additional width of the halo, I hope the names I gave to these parameters are self-explanatory.

enter image description here

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations.pathmorphing}
\pgfkeys{%
/pgf/decoration/.cd,
3d coil color/.store in=\TDCoilColor, 
3d coil color/.initial=black,
3d coil color=black,
3d coil width/.store in=\TDCoilWidth, 
3d coil width/.initial=0.4pt,
3d coil width=0.4pt,
3d coil dist/.store in=\TDCoilDist, 
3d coil dist/.initial=0.6pt,
3d coil dist=0.6pt,
3d coil opacity/.store in=\TDCoilOpacity, 
3d coil opacity/.initial=1,
3d coil opacity=1
}

\makeatletter % https://tex.stackexchange.com/a/219088/121799
\tikzset{get stroke color/.code={%
    \expandafter\global% Jump over, now we have \global
    \expandafter\let% Jump over now we have \global\let
    \expandafter\pgfsavedstrokecolor% Jump we have \global\let\pgf...
    \csname\string\color@pgfstrokecolor\endcsname% Finally expand this and put it at the end 
    },                                           % \global\let\pgf...{} in expanded form 
    restore stroke color/.code={\pgf@setstrokecolor#1},
}
\def\pgfpoint@onthreedcoil#1#2#3{%
  \pgf@x=#1\pgfdecorationsegmentamplitude%
  \pgf@x=\pgfdecorationsegmentaspect\pgf@x%
  \pgf@y=#2\pgfdecorationsegmentamplitude%
  \pgf@xa=0.083333333333\pgfdecorationsegmentlength%
  \advance\pgf@x by#3\pgf@xa%
  \advance\pgf@x by-\initialoffset pt%
}

% coil decoration
%
% Parameters: \pgfdecorationsegmentamplitude, \pgfdecorationsegmentlength,

\pgfdeclaredecoration{3d coil}{initial}
{ 
    \state{initial}[width=0.25*\pgfdecorationsegmentlength+\pgfdecorationsegmentaspect*\pgfdecorationsegmentamplitude,
    next state=coil, persistent precomputation={
    \tikzset{get stroke color}
    \pgfmathsetmacro{\initialoffset}{0.25*\pgfdecorationsegmentlength+\pgfdecorationsegmentaspect*\pgfdecorationsegmentamplitude}
  }]
  {%
    \pgfpathmoveto{\pgfpointorigin} 
    \pgfsetstrokecolor{\TDCoilColor}
    \pgfsetstrokeopacity{\TDCoilOpacity}
    \pgfsetlinewidth{1.5*\TDCoilWidth} 
    \pgfpathcurveto
    {\pgfpoint@oncoil{0    }{ 0.555}{1}}
    {\pgfpoint@oncoil{0.445}{ 1    }{2}}
    {\pgfpoint@oncoil{1    }{ 1    }{3}}
    \pgfusepath{stroke}
    \pgfcoordinate{TD@coilast}{\pgfpoint@oncoil{1    }{ 1    }{3}} 
    }
  \state{coil}[switch if less than=%
    1.25\pgfdecorationsegmentlength+%
    \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude+%
    \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude to last,
               width=+\pgfdecorationsegmentlength]
    { % line in the back
    %
    \pgfsetstrokecolor{\TDCoilColor}
    \pgfsetfillcolor{\TDCoilColor}
    \pgfsetstrokeopacity{\TDCoilOpacity}
    \pgfpathmoveto{\pgfpointanchor{TD@coilast}{center}}
    \pgfsetlinewidth{\TDCoilWidth} 
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{1.555}{ 1    }{4}}
    {\pgfpoint@onthreedcoil{2    }{ 0.555}{5}}
    {\pgfpoint@onthreedcoil{2    }{ 0    }{6}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{2    }{-0.555}{7}}
    {\pgfpoint@onthreedcoil{1.555}{-1    }{8}}
    {\pgfpoint@onthreedcoil{1    }{-1    }{9}}
    \pgfusepath{stroke} 
    %
    % white background for front thick part
    %
    \pgfsetstrokeopacity{1}
    \pgfsetstrokecolor{white}
    \pgfsetfillcolor{white}
    \pgfsetlinewidth{1.5*\TDCoilWidth+1.5*\TDCoilDist}
    \pgfpathmoveto{\pgfpoint@onthreedcoil{1    }{ 1    }{3}}
    \pgfpathmoveto{\pgfpoint@onthreedcoil{1    }{-1    }{9}}
    % draw forward
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0.445}{-1    }{10}}
    {\pgfpoint@onthreedcoil{0    }{-0.555}{11.25}}
    {\pgfpoint@onthreedcoil{0    }{ 0    }{12.5}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0    }{ 0.555}{13.25}}
    {\pgfpoint@onthreedcoil{0.445}{ 1    }{14.25}}
    {\pgfpoint@onthreedcoil{1    }{ 1    }{15}}
    % draw the curve back
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0.445}{ 1    }{14}}
    {\pgfpoint@onthreedcoil{0    }{ 0.555}{12.75}}
    {\pgfpoint@onthreedcoil{0    }{ 0    }{11.5}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0    }{-0.555}{10.75}}
    {\pgfpoint@onthreedcoil{0.445}{-1    }{10}}
    {\pgfpoint@onthreedcoil{1    }{-1    }{9}}
    \pgfusepath{stroke,fill} 
    % 
    % draw the thick foreground path
    %
    \pgfsetstrokecolor{\TDCoilColor}
    \pgfsetfillcolor{\TDCoilColor}
    \pgfsetstrokeopacity{\TDCoilOpacity}
    \pgfpathmoveto{\pgfpoint@onthreedcoil{1    }{ 1    }{3}}
    \pgfsetlinewidth{\TDCoilWidth} 
    % forward shifted +
    \pgfpathmoveto{\pgfpoint@onthreedcoil{1    }{-1    }{9}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0.445}{-1    }{10}}
    {\pgfpoint@onthreedcoil{0    }{-0.555}{11.25}}
    {\pgfpoint@onthreedcoil{0    }{ 0    }{12.5}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0    }{ 0.555}{13.25}}
    {\pgfpoint@onthreedcoil{0.445}{ 1    }{14.25}}
    {\pgfpoint@onthreedcoil{1    }{ 1    }{15}}
    % draw the curve back shfted -
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0.445}{ 1    }{14}}
    {\pgfpoint@onthreedcoil{0    }{ 0.555}{12.75}}
    {\pgfpoint@onthreedcoil{0    }{ 0    }{11.5}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{0    }{-0.555}{10.75}}
    {\pgfpoint@onthreedcoil{0.445}{-1    }{10}}
    {\pgfpoint@onthreedcoil{1    }{-1    }{9}}
    \pgfusepath{stroke,fill} % <- added
    \pgfcoordinate{TD@coilast}{\pgfpoint@onthreedcoil{1    }{ 1    }{15}} 
  }
  \state{last}[width=.25\pgfdecorationsegmentlength+%
    \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude+%
    \pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude,next state=final]
  {
    \pgfsetstrokecolor{\TDCoilColor}
    \pgfsetstrokeopacity{\TDCoilOpacity}
    \pgfsetlinewidth{\TDCoilWidth}
    \pgfpathmoveto{\pgfpointanchor{TD@coilast}{center}}
    \pgfpathcurveto
    {\pgfpoint@onthreedcoil{1.555}{ 1    }{4}}
    {\pgfpoint@onthreedcoil{2    }{ 0.555}{5}}
    {\pgfpoint@onthreedcoil{2    }{ 0    }{6}}
  }
  \state{final}
  {
    \pgfpathlineto{\pgfpointdecoratedpathlast}
    \pgfusepath{stroke}
    \tikzset{restore stroke color/.expand once=\pgfsavedstrokecolor}
  }
}
\makeatother

\begin{document}
\begin{tikzpicture}
\draw[decoration={3d coil color=blue,aspect=0.35, segment length=3.1mm, amplitude=3mm,3d coil},
decorate] (0,0) -- (0,3);
\draw[decoration={3d coil color=red,3d coil opacity=0.9,aspect=0.45, segment length=3.1mm, amplitude=3mm,3d coil},
decorate] (2,3) -- (2,0);
\draw[decoration={3d coil color=green!60!black,3d coil opacity=0.9,aspect=0.35, segment length=3.1mm, amplitude=3mm,3d coil},
decorate] (4,3) to[out=0,in=90] (6,0);
\end{tikzpicture}
\end{document}

FUN: The mandatory animation can be made with the same preamble + \usepackage{tikzmarmots} and

\begin{document}
\foreach \X [evaluate=\X as \Y using {sin(\X)}]in {0,10,...,350}
{
\begin{tikzpicture}
\path[use as bounding box] (-1,-0.2) rectangle (1,4);
\draw[decoration={3d coil color=blue,aspect=0.35, segment
length={(1.2+0.7*\Y)*1mm}, amplitude=3mm,3d coil},
decorate] (0,0) -- (0,2);
\begin{scope}[shift={(-0.9,1+0.5*\Y)}]
\marmot[teeth,whiskers]
\end{scope}
\end{tikzpicture}}
\end{document}

enter image description here

17
  • 7
    The decorations in pgf, it's the most difficult, wonderful work, bravo!
    – AndréC
    Sep 6, 2018 at 16:05
  • @AndréC Merci, but I am actually not really happy, What I would love to achieve is that it is not necessary to set the color, opacity and so on explicitly. And then there are more downsides. Assume I was able to achieve this, then the decomposition of the path in little segments has further downsides such as the fact that a dashed line will not look nice. So there is a lot of room for improvement...
    – user121799
    Sep 6, 2018 at 16:09
  • 4
    Another beautiful piece of marmot magic!
    – Max
    Sep 7, 2018 at 18:04
  • 1
    @Diaa Coil has a straight line because the length of one coil (i.e. the segment length) does not divide the length of the path. Coil2 uses a different approach in which the length of the coil is set to be 1/10 of the length of the path, which is why there is no straight line piece. To overcome the problem of leftovers you may use Jake's complete sines.
    – user121799
    Dec 17, 2018 at 22:39
  • 1
    @Diaa One would have to rewrite the style. The "problem" (I use parentheses because this is not at all a criticism of the nice macros) is that the path starts with an offset. If you replace in his code (90: 0.2 and 0.4) by (90: 0.2 and 0.4) coordinate(coilaux1-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) and (0,0)++(90: 0.2 and 0.4) by (0,0)++(90: 0.2 and 0.4) coordinate(coilaux0-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}), you can access the start as (coilaux0-1) and the end as (coilaux1-n) with an appropriate n.
    – user121799
    Dec 17, 2018 at 23:20
32

If you put negative values for aspect and amplitude, you can get the mirrored coil, add this in the @marmot's answer may complete the desired output; also I added an option using markings to get some similar drawing that uses scope and yscale to invert the marking, then a new variable to control the coil color,when the path is straight it has good result, markings path lacks bending good results.

EDIT: Added a control for marking step to improve bending results.

RESULT:

enter image description here

MWE:

\documentclass[tikz,border=20pt]{standalone}
\usetikzlibrary{decorations.pathmorphing,decorations.markings}

\begin{document}

\begin{tikzpicture}[
    CoilColor/.store in=\coilcolor,CoilColor=black,
    Step/.store in=\Step,Step=0.1,
    Coil/.style={
        double=black,
        draw=gray!50,
        decoration={
            #1,
            segment length=3mm,
            coil
            },
            decorate,
    },
    Coil2/.style={
        decorate,
        decoration={
            markings,
            mark= between positions 0 and 1 step \Step
            with {
                \begin{scope}[yscale=#1]
                \draw[xshift=9.2,fill,\coilcolor!70!black]
                    (0,0)++(-135: 0.2 and 0.4) 
                        .. controls +(-0.2,0) and +(-0.3,0) .. (90: 0.2 and 0.4)
                        .. controls +(-0.33,0) and +(-0.23,0) .. (-135: 0.2 and 0.4);                       
                \draw[white,line width=2pt]
                    (0,0)++(90: 0.2 and 0.4) 
                        .. controls +(0.3,0) and +(0.2,0) .. (-45: 0.2 and 0.4);
                \draw[fill=\coilcolor,\coilcolor]
                    (0,0)++(90: 0.2 and 0.4) 
                        .. controls +(0.3,0) and +(0.2,0) .. (-45: 0.2 and 0.4)
                        .. controls +(0.25,0) and +(0.35,0) .. (90: 0.2 and 0.4);
                \end{scope}                     
                    }
              }
        }
]
\draw[Coil={aspect=-0.3,amplitude=-3mm},blue] (0,0) -- ++ (0,-3);
\draw[Coil={aspect=0.3,amplitude=3mm},red] (1.5,0) -- ++ (0,-3);
\draw[Coil={aspect=0.3,amplitude=3mm},green!50!black] (3,0) arc (90:0:3);
\draw[Coil={aspect=-0.3,amplitude=-3mm}] (3,1) arc (90:0:4);

\draw[Coil2=-1,CoilColor=blue] (0,-4) -- ++ (0,-3);
\draw[Coil2=1,CoilColor=red] (1.5,-4) -- ++ (0,-3);
\draw[Coil2=-1,CoilColor=green!50!black,Step=0.065] (3,-4) arc (90:0:3);
\draw[Coil2=1,Step=0.048] (3,-3) arc (90:0:4);

\end{tikzpicture}
\end{document}

UPDATE: Acording to @marmot's suggestion closing the gaps and drawing all the variations, using \pgfdecoratedpathlength, /pgf/decoration/mark info/sequence number.

RESULT: enter image description here

MWE:

\documentclass[tikz,border=20pt]{standalone}
\usetikzlibrary{decorations.markings}

\begin{document}

\begin{tikzpicture}[
    CoilColor/.store in=\coilcolor,CoilColor=black,
    Step/.store in=\Step,Step=0.1,
    Width/.store in=\Width,Width=0.4,
    Coil2/.style={
        decorate,
        decoration={
            markings,
            mark= between positions 0 and 1 step \Step 
            with {
                \begin{scope}[yscale=#1]
                    \pgfmathparse{int(\pgfdecoratedpathlength/28.45*100*\Step)}
                    \edef\Hight{\pgfmathresult}
                    \ifnum\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}=1
                        \path (0,0)++(90: \Hight/200 and \Width) coordinate (b);
                    \fi
                    \ifnum\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}>1
                        \coordinate (b) at (d);
                    \fi
                    \path (b) arc (90:-135: \Hight/200 and \Width) coordinate (a);
                    \path (b) arc (90:-45: \Hight/200 and \Width) coordinate (c);
                    \path (b)++(\Hight/100,0) coordinate (d);
                    \draw[fill,\coilcolor!70!black]
                        (c)
                            .. controls +(-0.175,0) and +(-0.275,0) .. (d)
                            .. controls +(-0.325,0) and +(-0.225,0) .. (c);
                    \draw[white,line width=2pt]
                        (b)
                            .. controls +(0.3,0) and +(0.2,0) .. (c);
                    \draw[fill,\coilcolor]
                        (b)
                            .. controls +(0.275,0) and +(0.175,0) .. (c)
                            .. controls +(0.225,0) and +(0.325,0) .. (b);
                \end{scope}
            }
        }
    }
]

\draw[Coil2=-1,CoilColor=red,Step=0.15] (0.5,0) -- ++ (0,-3);
\draw[Coil2=1.5,CoilColor=magenta] (1.5,0) -- ++ (0,-3);

\draw[Coil2=1,CoilColor=green!70!black,Step=0.02] (0,-4) 
    to [in=90,out=0] ++(2.5,-1)
    to [in=180,out=-90] ++(2.5,-1)
    to [in=-90,out=0] ++(2,1.5)
    to [in=-90,out=90] ++(0.5,3) arc (0:90:2);

\draw[Coil2=-1,CoilColor=green!50!cyan,Step=0.02] (0,-5) 
    to [in=90,out=0] ++(1.5,-1)
    to [in=180,out=-90] ++(4,-1)
    to [in=-90,out=0] ++(3,2.5)
    to [in=-90,out=90] ++(0.5,4.5) arc (0:90:2);

\draw[Coil2=1,CoilColor=cyan!30!blue,Step=0.05] (5.7,-2) arc (360:0:1.5);
\draw[Coil2=-1,CoilColor=cyan!70!blue,Step=0.05] (6.5,-2) arc (360:0:1.5);

\end{tikzpicture}
\end{document}
0

You must log in to answer this question.

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