Half-drawn crossings when using `double` with `knots`

There are a couple of things going on here, one of which is related to how best to draw pictures like this (which I should probably add to the documentation), and one of which reveals a small bug in the knots package.

When drawing a celtic-style knot with the knots package then there are a few issues with how double paths turn out. Over time, via a few questions here, then a best way of doing these knots has emerged which isn't the obvious way.

More importantly, though, is that because your control points are very close to intersections and your paths are very wide then you are falling foul of a bug in how end tolerance is used. This key is used to tell the knots library what "near an endpoint" means. This is used twice, once to throw out spurious intersections where one segment "intersects" the next segment. For this test, you want to set end tolerance to be quite small since your control points are close to the (genuine) intersection points (the option ignore endpoint intersections=false is what is causing the spurious intersection in the lower left corner; since none of your control points is actually at an intersection, by removing this option and keeping end tolerance small you can get rid of this intersection without affecting the rest of the picture).

But end tolerance is also used in another place. When the algorithm detects an intersection then it draws the upper strand again in the vicinity of the intersection. Normally, it just draws the relevant segment of the path. But if that segment ends near to the intersection point then it also draws the next (or previous, as applicable) segment. And the algorithm uses end tolerance again here. So with end tolerance set to be very small, this means that a segment that should be drawn is not because the intersection point is found to be further from the endpoint of the segment. What I should use here is the clipping radius.

This is, I think, what is going on with your half-crossing. There's a further step in the routine when checking self-intersections which (possibly) splits bézier curves in two to ensure that they don't themselves self-intersect. This is (probably) happening to that diagonal path and then, due to end tolerance being small, only part of that path is being rendered.

Here's your code:

\documentclass{article}
%\url{https://tex.stackexchange.com/q/580472/86}
\usepackage{tikz}

\usetikzlibrary{
  knots,
  hobby,
}

\tikzset{
  knot diagram/every knot diagram/.append style={
    consider self intersections=true,
    %        ignore endpoint intersections=false,
    end tolerance=1pt,
    clip width=1,
    background color=blue!40!black,
    only when rendering/.style={
      basic strand
    },
    every intersection/.style={
      crossing strand
    },
  },
  basic strand/.style={
    ultra thick,
    draw=blue!40!black,
    double=white,
    double distance=10pt
  },
  crossing strand/.style={
    line width=13.2pt,
    only when rendering/.style={%
      draw=white,%
      line width=10pt,
      double=none,
    }
  }
}

\begin{document}
\begin{tikzpicture}
    \begin{knot}[
%        draft mode=crossings,
        flip crossing/.list={4,6,7,10,12}
        ]
    \strand
        (0.5,0.5) to[out=-5,in=-135]
        (1.8,0.8) to[out=45,in=-135]
        (4.25,3.25) to[out=45,in=135]
        (5.75,3.25) to[out=-45,in=135]
        (8.2,0.8) to[out=-45,in=-175]
        (9.5,0.5) to[out=85,in=-45]
        %
        (9.2,1.8) to[out=135,in=-45]
        (7.75,3.25) to[out=135,in=45]
        (6.25,3.25) to[out=-135,in=45]
        (3.75,0.75) to[out=-135,in=-45]
        (2.25,0.75) to[out=135,in=-45]
        (0.8,2.2) to[out=135,in=-95]
        (0.5,3.5) to[out=5,in=135]
        %
        (1.8,3.2) to[out=-45,in=135]
        (4.25,0.75) to[out=-45,in=-135]
        (5.75,0.75) to[out=45,in=-135]
        (8.2,3.2) to[out=45,in=175]
        (9.5,3.5) to[out=-85,in=45]
        %
        (9.2,2.2) to[out=-135,in=45]
        (7.75,0.75) to[out=-135,in=-45]
        (6.25,0.75) to[out=135,in=-45]
        (3.75,3.25) to[out=135,in=45]
        (2.25,3.25) to[out=-135,in=45]
        (0.8,1.8) to[out=-135,in=95] cycle;
    \end{knot}
    \useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}

\begin{tikzpicture}
    \begin{knot}[
%        draft mode=crossings,
        flip crossing/.list={2,4,6,7,10,12}
        ]
    \strand
        ([closed]0.5,0.5) to[out=-5,in=-135]
        (1.9,0.9) to[out=45,in=-135]
        (4.25,3.25) to[out=45,in=135]
        (5.75,3.25) to[out=-45,in=135]
        (8.1,0.9) to[out=-45,in=-175]
        (9.5,0.5) to[out=85,in=-45]
        %
        (9.1,1.9) to[out=135,in=-45]
        (7.75,3.25) to[out=135,in=45]
        (6.25,3.25) to[out=-135,in=45]
        (3.75,0.75) to[out=-135,in=-45]
        (2.25,0.75) to[out=135,in=-45]
        (0.9,2.1) to[out=135,in=-95]
        (0.5,3.5) to[out=5,in=135]
        %
        (1.9,3.1) to[out=-45,in=135]
        (4.25,0.75) to[out=-45,in=-135]
        (5.75,0.75) to[out=45,in=-135]
        (8.1,3.1) to[out=45,in=175]
        (9.5,3.5) to[out=-85,in=45]
        %
        (9.1,2.1) to[out=-135,in=45]
        (7.75,0.75) to[out=-135,in=-45]
        (6.25,0.75) to[out=135,in=-45]
        (3.75,3.25) to[out=135,in=45]
        (2.25,3.25) to[out=-135,in=45]
        (0.9,1.9) to[out=-135,in=95] cycle;
    \end{knot}
    \useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}
\end{document}

Celtic-style knots

I've just uploaded the fixed version to github.

(But I can still see slight artefacts on the upper one of these, which suggests that I might not have the fix quite right yet -- for anyone mathematically inclined, it might be due to me using the l^1-norm for speed instead of the l^2-norm so I might need a factor of sqrt(2) in there somewhere.)


I offer you a different way to do it, directly with tikz. My drawing is Celtic, because I don't really know how you do want to overlap the lines. There is an additional example for you to see how to overlap the lines arbitrarily.

This is my code:

\begin{document}
\begin{tikzpicture}[line join=round, line cap=round, thick, blue, fill=blue!10]
  % Coordinates
  \pgfmathsetmacro\r{sqrt(2)}  
  \foreach\x in {1,...,5} \foreach\y in {1,2}
  {
    \coordinate (\x-\y-O) at (1.5*\r*\x,1.5*\r*\y);
    \coordinate (\x-\y-N) at ($(\x-\y-O)+(0,0.5*\r)$);
    \coordinate (\x-\y-S) at ($(\x-\y-O)-(0,0.5*\r)$);
    \coordinate (\x-\y-E) at ($(\x-\y-O)+(0.5*\r,0)$);
    \coordinate (\x-\y-W) at ($(\x-\y-O)-(0.5*\r,0)$);
  }
  % Middle section
  \foreach\x in {2,3,4}
  {
    \pgfmathtruncatemacro\xx{\x-1}
    \filldraw (\x-1-N) ++ (225:1) arc (225:315:1) --++ (45:1.5) --++
              (315:0.5) --++ (225:1.5) --++ (0,0) arc (315:225:1.5) --cycle;
    \filldraw (\x-2-W) --++ (315:2.5) --++ (225:0.5) --++ (135:2.5) -- cycle;
    \filldraw (\xx-2-S) --++ (45:1.5) --++ (0,0) arc (135:45:1.5) --++
              (225:0.5) --++ (0,0) arc (45:135:1) --++ (225:1.5) -- cycle;
  }
  % Corners
  \foreach \x/\y/\c/\a in {1/1/N/0, 1/2/E/270, 5/1/W/90, 5/2/S/180}
  {
    \begin{scope}[shift={(\x-\y-\c)},rotate=\a]
      \filldraw (0,0) --++ (135:0.5) --++ (0,0) arc (135:180:1.5) --++ (270:1.5-0.5*\r) --++
                (0:1.5-0.5*\r) --++ (0,0) arc (270:315:1.5) --++ (45:1.5) --++ (135:0.5) --++
                (225:1.5) --++ (0,0) arc (315:270:1) --++ (180:1-0.5*\r) --++ (90:1-0.5*\r) --++
                (0,0) arc (180:135:1) -- cycle;
    \end{scope}
  }
  % Non-celtic example (superposed, comment it if you want)
  \filldraw[draw=red,fill=red!10] (2-1-N) --++ (225:1.5) --++ (0,0) arc (315:270:1.5) --++
                (180:1.5-0.5*\r) --++ (90:1.5-0.5*\r) --++ (0,0) arc (180:135:1.5) --++ (45:2) --++
                (0,0) arc (135:45:1.5) --++ (315:3) --++ (225:0.5) --++ (135:3) --++
                (0,0) arc (45:135:1) --++ (225:2) --++ (0,0) arc (135:180:1) --++
                (270:1-0.5*\r) --++ (0:1-0.5*\r) --++ (0,0) arc (270:315:1) --++ (45:1.5) -- cycle;
% Auxiliar grid of squares
%  \foreach\x in {1,...,5} \foreach\y in {1,2}
%  {
%    \draw[thin,black,dashed] (\x-\y-E) -- (\x-\y-N) -- (\x-\y-W) -- (\x-\y-S) -- cycle;
%  }
\end{tikzpicture}
\end{document}

And the drawing: enter image description here