1

Is it possible to define a decoration/postaction, for drawing a double line so that a self intersecting line will draw on top of itself? To show what I mean see these spirals:

\documentclass[tikz, border=1cm]{standalone}
\begin{document}
\begin{tikzpicture}
\draw[red, double=yellow, thick, domain=0:pi, smooth, samples=200] plot (\x, {cos(10*\x r)} , {sin(10*\x r)} );
\begin{scope}[yshift=-3cm]
\foreach \i in {1,...,10}
\draw[red, double=yellow, thick, domain=pi*(\i-1)/10:pi*\i/10, smooth, samples=200] plot (\x, {cos(10*\x r)} , {sin(10*\x r)} );
\end{scope}
\end{tikzpicture}
\end{document}

Two spirals

The top spiral shows the effect of a normal double line and the bottom spiral shows the desired result. I wish the result done with just one \draw command to avoid rendering artefacts and make the smooth option work across the whole spiral.

Ultimately, I want to be able to use white as the outer color and thereby creating a crossing effect. To be able to better answer questions on this site e.g. Conical and cylindircal spirals

I was thinking that it should be possible by making the double on small segments of the path as it is being drawn. A naive approach like this:

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary {decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
\draw[yellow, 
decorate, decoration={zigzag, segment length=1mm, amplitude=0mm},
preaction={draw, ultra thick, red},
domain=0:pi, samples=200] plot (\x, {cos(10*\x r)} , {sin(10*\x r)} );
\end{tikzpicture}
\end{document}

does not work as the preaction is applied to the whole path and not the segments.

A even better solution would be if the path could clip itself, so that the crossing would look nice on a non-white background. - Probably quite complicated.

2 Answers 2

3

Here is one way with the show path construction.

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{decorations.pathreplacing}
\begin{document}
\begin{tikzpicture}[path decomposition/.style={%
    postaction={decoration={show path construction,
    lineto code={
      \draw[#1]  (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
    },
    curveto code={
      \draw[#1]  (\tikzinputsegmentfirst) .. controls
        (\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
        ..(\tikzinputsegmentlast) ;
    },
    closepath code={
      \draw[#1]  (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast) {closepath};} }
    ,decorate}}]
\draw[red, double=yellow, thick, domain=0:pi, smooth, samples=200,
path decomposition={red, double=yellow, thick}] plot (\x, {cos(10*\x r)} , {sin(10*\x r)} );
\begin{scope}[yshift=-3cm]
\foreach \i in {1,...,10}
\draw[red, double=yellow, thick, domain=pi*(\i-1)/10:pi*\i/10, smooth, samples=200] plot (\x, {cos(10*\x r)} , {sin(10*\x r)} );
\end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Please note that there are already complete styles for this in this answer.

10
  • You are fast :o) . Also thanks for the link - I will study it. Nov 28, 2020 at 17:04
  • It is a very beautiful solution. At first, I could not see how it could possible be more elegant. -but at closer look, there are many rendering artefacts. It can be spotted on your picture, but it is easier seen with black on white. There are many hairline spikes and gaps. I do not understand the spikes(I believe that double is implemented by drawing fat line first and then center - the center should not be able to poke out.). Maybe the gaps could be corrected with shorten!? Nov 28, 2020 at 17:18
  • I will probably accept your answer, but I would like your opinion on wether the artefacts are possibly corrected. Nov 28, 2020 at 17:19
  • 1
    @hpekristiansen The artifacts are real, of course, since the path gets decomposed, but how they look like does depend on the viewer. I get very different results with acroread and preview.
    – user229669
    Nov 28, 2020 at 18:07
  • 1
    @hpekristiansen The decoration really just hooks into the segments as they get created by the path. In your case, the segment length is controlled by samples=200, which produces 199 plot segments, each of which is a Bezier curve since you use the smooth key. That is, the segment length is entirely specified by the path you decorate.
    – user229669
    Nov 28, 2020 at 18:16
4

The knots TikZ library handles this sort of thing. There's a slight issue with using the plot drawing command because that creates a lot of very short lines and that's not great for the way that knots works since it looks for intersections between subpaths. Fortunately, using the hobby library I can reduce the number of samples considerably as it interpolates using bezier curves.

The knots library works by redrawing just part of the curve at the intersections to produce the overpass effect.

Using the double option with the knots library can produce artefacts when the PDF is viewed (but not when it is printed). The method for removing them is detailed at problem with "crop circles" in tikz knot library

Here's the code:

\documentclass{article}
%\url{https://tex.stackexchange.com/q/572737/86}
\usepackage{tikz}
\usetikzlibrary{knots,hobby}

\tikzset{
  basic strand/.style={
    red,
    double=yellow,
    double distance=1pt,
  },
  crossing strand/.style={
    line width=1.8pt,
    only when rendering/.style={%
      draw=yellow,%
      line width=1pt,
      double=none,
    }
  }
}

\begin{document}
\begin{tikzpicture}[use Hobby shortcut]
\begin{knot}[
  consider self intersections=true,
  ignore endpoint intersections=false,
  background colour=red,
  every intersection/.style={
    crossing strand
  },
  only when rendering/.style={
    basic strand
  },
  clip width=1
]
\strand (0,1,0) \foreach \x in {1,...,80} { .. (\x/80*pi, {cos(22.5*\x )} , {sin(22.5*\x )} ) };
\end{knot}
\end{tikzpicture}
\end{document}

Result:

Coil with overlay effect

3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.