6

I'm using the knots tikzlibrary to draw some knots, and wanted to orient my knots, i.e. add an arrow. I use a decoration style which I've called "arrowat", which inserts an arrow at the desired spot (e.g. \draw[arrowat=0.5] will yield an arrow halfway along the resulting line). It is defined as follows

\tikzset{% 
    arrowat/.style={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\arrow[xshift=2pt]{>}}}}
    }
}

However, some problems arise when I try to use this style on a knot: At certain spots, things work just fine, but if I try to draw an arrow at certain other spots, multiple arrows (and gaps in the line) appear. Below is a MWE, showing both a case in which things work just fine (left) and one where they don't (right). My question is: How do I fix this, or rather prevent it from happening?

enter image description here

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,knots}

\tikzset{% 
    arrowat/.style={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\arrow[xshift=2pt]{>}}}}
    }
}
\begin{document}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick, arrowat=0.8] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
\end{knot}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick, arrowat=0.5] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
    \end{knot}
\end{tikzpicture}

\end{document}
7

I do not have a true (i.e. elegant) solution. Just curious to partly understand what's going on and checked how often TikZ thinks it is at position 0.5. In this example this is 10 times, you can verify this by uncommenting \typeout{\number\value{arrowcount}}. Then one can add a switch that says at which of these the arrow is really to be drawn. The corresponding style is called conditional arrow at.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,knots}
\newcounter{arrowcount}
\tikzset{% 
    arrowat/.style={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\arrow[xshift=2pt]{>}}}}
    },
    conditional arrow at/.style 2 args={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\stepcounter{arrowcount}%
                %\typeout{\number\value{arrowcount}}%
                \ifnum\value{arrowcount}=#2
                \arrow[xshift=2pt]{>}%
                \fi}}}
    },
}
\begin{document}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick, arrowat=0.8] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
\end{knot}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick,conditional arrow at={0.5}{6}] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
   \end{knot}
\end{tikzpicture}

\end{document}

enter image description here

The situation improves by a factor 2 (as expected) when using the only when rendering key. Then you have "only" 5 slots, and each of them really leads to an arrow.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,knots}
\newcounter{arrowcount}
\tikzset{% 
    arrowat/.style={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\arrow[xshift=2pt]{>}}}}
    },
    conditional arrow at/.style 2 args={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\stepcounter{arrowcount}%
                \typeout{\number\value{arrowcount}}%
                \ifnum\value{arrowcount}=#2
                \arrow[xshift=2pt]{>}%
                \fi}}}
    },
}
\begin{document}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick, arrowat=0.8] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
\end{knot}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick,only when rendering/.style={conditional arrow at={0.5}{3}}] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
   \end{knot}
\end{tikzpicture}

\end{document}

So it seems that the problem is that the path gets decomposed into segments. This tells us that we can attach the arrow to an invisible path instead.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,knots}
\newcounter{arrowcount}
\tikzset{% 
    arrowat/.style={%
        postaction={decorate,decoration={
                markings,
                mark=at position #1 with {\arrow[xshift=2pt,opacity=1]{>}}}}
    },
}
\begin{document}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \strand [thick, arrowat=0.8] (0,0)
    to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0);
\end{knot}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{knot} [consider self intersections, ignore endpoint intersections=false, clip width=7, flip crossing=3]
    \def\mypath{(0,0) to [out=180, in=270] (-1,1)
    to [out=90, in=180] (1,2.5)
    to [out=0, in=90] (3,1)
    to [out=270, in=0] (2,0)
    to [out=180, in=270] (-0.2,2.5)
    to [out=90, in=180] (1,3.8)
    to [out=0, in=90] (2.2,2.5)
    to [out=270, in=0] (0,0)}
    \draw[thick,opacity=0,arrowat=0.55] \mypath;
    \strand [thick] \mypath;
   \end{knot}
\end{tikzpicture}

\end{document}

enter image description here

This might be the most elegant of these proposals, and also reveals that the "true" arrow at 0.5 is obscured by a crossing.

| improve this answer | |
  • 2
    Your analysis is spot on. When consider self intersections is set then the path is decomposed into segments to find the self-intersections and to render the crossings. Paths are rendered multiple times, both as background "wipe out" paths and as the actual path, so the decoration is being applied multiple times. To see a little bit of what's going on, try adding background colour=yellow! So your solution of using an invisible path is really the simplest solution. – Andrew Stacey Mar 27 at 20:29
  • @AndrewStacey Thanks! – user194703 Mar 27 at 20:32
  • 1
    Thank you very much for your comprehensive answer, and also thank you, @AndrewStacey, for giving your official stamp of approval ;-) – Danu Mar 28 at 10:41

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.