11

I'm trying to draw some knots with TikZ. I've got this far:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{knots}
\begin{document}
$\begin{tikzpicture}[domain=-2:2, scale=0.3]
\begin{knot} [clip width=4]
\strand (0,2) to [out=down, in=down, looseness=1.8] (1.5,0);
\strand (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2);
\end{knot}
\draw[dashed] (0,0) circle (2cm);
\end{tikzpicture}$
\end{document}

The point it, that I need a visible "top and bottom" at each crossing (i.e. nonzero clip width). In the above example, the crossings don't work properly. However, if I draw a different (larger) knot such as:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{knots}
\begin{document}
$\begin{tikzpicture}[domain=-2:2, scale=0.3]
\begin{knot} 
\strand (-1.3,1.3) to [out=right, in=right, looseness=2.2] (-1.3,-1.3);
\strand (1.3,1.3) to [out=left, in=left, looseness=2.2] (1.3,-1.3);
\end{knot}
\draw[dashed] (0,0) circle (2cm);
\end{tikzpicture}$
\end{document}

everything is fine. What is causing this strange behavior?

JMP
  • 3,238
ulead86
  • 511
  • 1
  • 3
  • 13

2 Answers2

9

The problem is most likely due to the fact that your crossings are too close to the ends of two strands, making them fail the "end tolerance" distance test. More on this below.


The knots package does some complicated stuff to try to ensure that it gets all possible intersections. Sometimes, this is over complicated so there are options to turn off some of the more extensive routines - and some aren't enabled by default. To make yours work, you need to add the option ignore endpoint intersections=false option to the knot environment.

Note that you mustn't have a space between the \begin{knot} and the start of the optional environment.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/217719/86}
\usepackage{tikz}
\usetikzlibrary{knots}
\begin{document}
\begin{tikzpicture}[domain=-2:2, scale=0.3]
\begin{knot}[
  clip width=4,
  ignore endpoint intersections=false,
]
\strand (0,2) to [out=down, in=down, looseness=1.8] (1.5,0);
\strand (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2);
\end{knot}
\draw[dashed] (0,0) circle (2cm);
\end{tikzpicture}
\end{document}

Note that in investigating what was going on here, I uncovered a bug or two in the library and updated the version on github.

Update: 2014-12-15 One thing that was puzzling me here was as to why this particular crossing was being affected by the test involved in ignore endpoint intersections since this isn't an endpoint and I thought I'd planned the knot code so that this would never become an endpoint (which can happen as paths get split into pieces). In short, the endpoint test ignores crossings that are considered too close to the ends of strands. The alternative solution in the comments gave the game away. The scale=0.3 makes the diagram so small that just about every point inside it is within the default tolerance of the endpoints of the strands (note that because the path is split in to two strands, there is an endpoint at (1.5,0). Note also that it is possible to use a single strand here using the key consider self intersections but this still has the end point issue.). The solution above works by switching off the "are we close to the end of a strand?" test. An alternative is to make the test more rigorous by decreasing the tolerance. Fortunately, I thought of that when I wrote the original package (though had forgotten it since!) and there is a key end tolerance=<dimen> to refine the test. Thus:

\begin{tikzpicture}[domain=-2:2, scale=.3]
\begin{knot}[
  clip width=4,
  end tolerance=1pt,
]
\strand (0,2) to [out=down, in=down, looseness=1.8]
(1.5,0);
\strand (1.5,0) to [out=up, in=up, looseness=1.8]
(0,-2);
\end{knot}
\draw[dashed] (0,0) circle (2cm);
\end{tikzpicture}

also works.

Danu
  • 968
Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
  • (+1) Could have sworn I tried that... – cfr Dec 14 '14 at 01:26
  • @cfr Did you remove the space? If you don't delete the space between \begin{knot} and the [...] then the part in [...] isn't taken as the optional argument to the knot environment but is passed on to \tikzset which doesn't have the same effect. – Andrew Stacey Dec 14 '14 at 01:27
  • Frankly, I'm not sure at this point. Very likely not as that is not something I would have spontaneously thought of in a TiKZ context and I only skimmed the documentation, having never tangled with knots before that I can recall. So I'm sure that must be it. – cfr Dec 14 '14 at 01:35
  • 1
    @cfr Interestingly, the necessity of no spaces is because the knot environment is defined using \NewDocumentEnvironment from xparse rather than the standard \newenvironment. – Andrew Stacey Dec 14 '14 at 01:54
  • @Loop Space: one more information: A collegue of mine gave me this knot-code: \begin{tikzpicture}[scale=1] \begin{knot}[clip width=5] \strand[ultra thick] (0,2) to [out=down, in=down, looseness=1.8] (1.5,0); \strand[ultra thick] (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2); \flipcrossings{1}; \end{knot} \draw[dashed] (0,0) circle (2cm); \end{tikzpicture} which is working as intended. – ulead86 Dec 15 '14 at 08:42
  • @ulead86 The difference between the two diagrams comes in the scale=X option on the outer tikzpicture. The issue in your diagram is that the crossing is being ignored because it is failing a distance test. By scaling up the diagram, you effectively lower the tolerance on that distance test and so make it more likely that the crossing will get seen. – Andrew Stacey Dec 15 '14 at 09:49
  • @ulead86 See updated answer. That gave me the clue to what was actually going on here. Thanks. – Andrew Stacey Dec 15 '14 at 10:03
  • @LoopSpace Even scaling the outer tikzpicture causes this problem for me (and lowering end tolerance does fix this). I hope you don't mind if I edit your answer a bit to make this solution more prominent? I almost missed it because it's at the bottom of your post. Of course, you can always rollback etc. – Danu Feb 17 '16 at 15:41
  • @Danu Looks fine to me. Always nice to hear that someone's using my packages. – Andrew Stacey Feb 17 '16 at 19:30
  • Sorry to draw your attention in this (sneaky) way, but I have a new question concerning small knots. Would you perhaps be able to help out? :) – Danu Dec 03 '16 at 07:25
  • @Danu You have accepted an answer on that new question. Do you still want me to take a look at it? – Andrew Stacey Dec 04 '16 at 17:42
  • @LoopSpace I think the question has been satisfactorily answered---I'm sorry to have bothered you this way! PS: The knots package/tikz library is awesome :-) – Danu Dec 04 '16 at 18:03
  • @Danu No problem! Just wanted to be sure before I looked at it. Glad to see that you're still using the package. – Andrew Stacey Dec 04 '16 at 18:30
4

This works but I have no idea why:

\documentclass[tikz, border=5pt, mult, varwidth]{standalone}
\usetikzlibrary{knots}
\begin{document}
  \begin{tikzpicture}[domain=-2:2, scale=0.3]
    \begin{knot} [clip width=4]
      \strand (0,2) to [out=down, in=down, looseness=1.8] (1.5,0);
      \strand (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2);
      \strand (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2);
    \end{knot}
    \draw[dashed] (0,0) circle (2cm);
  \end{tikzpicture}
\end{document}

knotted

Alternatively, use the knot=colour and knot gap=factor styles:

\documentclass[tikz, border=5pt, mult, varwidth]{standalone}
\usetikzlibrary{knots}
\begin{document}
  \begin{tikzpicture}[domain=-2:2, scale=0.3, knot gap=7]
      \draw [knot=black] (0,2) to [out=down, in=down, looseness=1.8] (1.5,0) ;
      \draw [knot=black] (1.5,0) to [out=up, in=up, looseness=1.8] (0,-2);
    \draw[dashed] (0,0) circle (2cm);
  \end{tikzpicture}
\end{document}

knotted again

cfr
  • 198,882
  • Thanks for your reply. Now I'm interested, why your first solution is working and my (nearly the same try) doesn't. – ulead86 Dec 13 '14 at 10:42
  • @ulead86 I don't know. I am interested in the same question. I have no idea why drawing part of the path again should work, but drawing it once does not. – cfr Dec 13 '14 at 17:27