5

I have troubles with self intersections in the knots library. Consider the following:

\documentclass[tikz,border=1pt]{standalone}    
\usetikzlibrary{calc,knots}    

%set default length and width parameters
\def\x{.7}
\def\y{1}

\begin{document}
 \begin{tikzpicture}
  \begin{knot}[consider self intersections=true]
   \strand (0,-\y) .. controls +(0,0) 
      .. (0,0) .. controls +(0,\x/3) and +(0,\x/3) 
      .. (\x/2,0) .. controls +(0,-\x/3) and +(0,-\x/3) 
      .. (0,0) .. controls +(0,0) .. (0,\y);
  \end{knot}
 \end{tikzpicture}
\end{document}

Which produces this graph
self_intersection
The self intersection of the loop is not detected by knots. Is there a way to fix this ?

Edit:
It somehow has to do with the end tolerance parameter. Depending on it knots detect one or several intersections at the crossing.
The following pictures are taken for end tolerance = 0.066 and 0.01.
self_intersection_2 self_intersection_2_1 self_intersection_3 self_intersection_3_1
Which is still somewhat strange because I would have expected something of the form
self_intersection_3
This last picture I only managed to create by manually splitting the loop into two strands.

1
  • 3
    Because the knots package splits the path into components, it is best practice to keep the intersections away from the ends of the defining pieces. If you want that exact picture then I see that that's not possible, in which case AndréC's answer is probably the best you'll get. But if you're prepared to deviate very slightly from that picture, a more robust solution is possible. Nov 1, 2019 at 17:20

3 Answers 3

3

As you say, it is the end tolerance parameter that is at stake. But, I redefined your path because its departure and arrival use uselessly beziers curves to draw straight lines. This way I get the result you want.

screenshot

\documentclass[tikz,border=5mm]{standalone}    
\usetikzlibrary{calc,knots}    

%set default length and width parameters
\def\x{.7}
\def\y{1}

\begin{document}
 \begin{tikzpicture}
  \begin{knot}[consider self intersections,end tolerance=.01pt,
  %draft mode=crossings
  ]
   \strand (0,-\y) %.. controls +(0,0) <-- useless beziers curve
      %.. 
      --(0,0) .. controls +(0,\x/3) and +(0,\x/3) 
      .. (\x/2,0) .. controls +(0,-\x/3) and +(0,-\x/3) 
      .. (0,0) %.. controls +(0,0) .. <- useless beziers curve
       --(0,\y);
  \end{knot}
 \end{tikzpicture}
\end{document}
3

LoopSpace explained very well what the issue is, and how to fix it. Here I'd like to draw your attention to an alternative, which has been used in a very similiar application. This alternative is by no means "better" than, or even comparable to, the knots package. The reason why I am mentioning it here is that it gives a rather reasonable output without the need modify your path, or to tune parameters.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{decorations.pathreplacing}
\begin{document}
\begin{tikzpicture}[rubout/.style={/utils/exec=\tikzset{rubout/.cd,#1},
 decoration={show path construction,
      curveto code={
       \draw [white,line width=\pgfkeysvalueof{/tikz/rubout/line width}+2*\pgfkeysvalueof{/tikz/rubout/halo}] 
        (\tikzinputsegmentfirst) .. controls
        (\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)  ..(\tikzinputsegmentlast); 
       \draw [line width=\pgfkeysvalueof{/tikz/rubout/line width},shorten <=-0.1pt,shorten >=-0.1pt] (\tikzinputsegmentfirst) .. controls
        (\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb) ..(\tikzinputsegmentlast);  
      }}},rubout/.cd,line width/.initial=0.6pt,halo/.initial=0.6pt]
  \def\x{.7}
  \def\y{1}
  \draw[rubout,decorate] (0,-\y) .. controls +(0,0) 
      .. (0,0) .. controls +(0,\x/3) and +(0,\x/3) 
      .. (\x/2,0) .. controls +(0,-\x/3) and +(0,-\x/3) 
      .. (0,0) .. controls +(0,0) .. (0,\y);\end{tikzpicture}
\end{document}

enter image description here

3
  • I hadn't come across the rubout decoration before. It is a "cheap" version of what the knots package does, in that the knots package can handle earlier parts of the path rubbing out later parts, and it can handle more complicated situations, such as when a component of the path goes over itself. But for when it works, this looks a useful technique. Nov 1, 2019 at 20:14
  • @LoopSpace Yes, I agree that this is by no means comparable in scope, but there are applications where this thingy does the job.
    – user194703
    Nov 1, 2019 at 20:17
  • 1
    Absolutely! I didn't mean "cheap" in a negative way. The knots package can take its time finding the intersections so if the strand is drawn correctly first time then this can be a quick way to achieve the desired outcome. Nov 1, 2019 at 20:22
2

Thanks for all the answers !
Following the suggestion of Loop Space I created a more stable variant by slightly deviating from the initial picture. I also realized that, for this picture, using arc instead of beziers curves keeps the code more readable, but that's just taste I guess.

\documentclass[tikz, border=5mm]{standalone}
\usetikzlibrary{calc,knots}
% basic distances for tikz
\def\y{1}
\def\r{-.2}

\begin{document}        
  \begin{tikzpicture}
    \begin{knot}[consider self intersections, end tolerance=1pt]
      \strand (0,-\y) to (0,0) arc (0:90:\r) arc (90:270:\r*.6) arc (270:360:\r)  
                      to (0,\y);
    \end{knot}
  \end{tikzpicture}  
\end{document}

loop

1
  • +1 but I would recommend replacing \x and \y by some other macros, in particular if you load calc.
    – user194703
    Nov 1, 2019 at 22:00

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.