How to draw a coil such that you can see if it's right or left handed?
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.
\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}
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:
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:
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}