Update: This is now available on CTAN (see above). Bugfixes and improvements will generally be available on github before being uploaded to CTAN. Note that that repository is quite cluttered, the relevant .dtx
file is called spath3.dtx
. This generates all the necessary files.
Update: The code has undergone considerable revision following extensive discussion with Jamie in the chat room From Answers to Packages. The code can now be downloaded from the TeX-SX Launchpad Project. The necessary files are knots.dtx
and spath.dtx
. The file knots_test.tex
contains some example code. To create the .sty
files from the .dtx
, run tex <file>.dtx
. Alternatively, running latex (or pdflatex) on knots_test.tex
with shell escapes enabled will automatically generate the .sty
files.
Okay, here's my first attempt at implementing what we discussed in chat. It is certainly a bit rough around the edges, and I give absolutely no guarantees that it won't TeX your cat instead.
Code:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections}
\makeatletter
\newcounter{knot@strings}
\newif\ifknot@draftmode
\tikzoption{save knot path}{\tikz@addmode{\pgfsyssoftpath@getcurrentpath\knot@tmppath\expandafter\global\expandafter\let#1=\knot@tmppath}}
\tikzoption{use knot path}{\tikz@addmode{\expandafter\pgfsyssoftpath@setcurrentpath#1}}
\tikzset{
knot/draft mode/.is if=knot@draftmode
}
\newenvironment{knot}[1][]{%
\tikzset{#1}%
\setcounter{knot@strings}{0}}{%
\foreach \knot@str in {1,...,\the\value{knot@strings}} {
\expandafter\expandafter\expandafter\draw\expandafter\expandafter\expandafter[\csname knot@string@opts@\knot@str\endcsname,use knot path=\csname knot@string@\knot@str\endcsname] (0,0);
\ifknot@draftmode
\begingroup
\let\pgfsyssoftpath@movetotoken=\pgfqpoint
\let\pgfsyssoftpath@linetotoken=\pgfqpoint
\let\pgfsyssoftpath@curvetotoken=\pgfqpoint
\let\pgfsyssoftpath@curvetosupportatoken=\pgfqpoint
\let\pgfsyssoftpath@curvetosupportbtoken=\pgfqpoint
\csname knot@string@\knot@str\endcsname
\global\pgf@xa=\pgf@x
\global\pgf@ya=\pgf@y
\endgroup
\node[circle,fill=white,fill opacity=.5] at (\pgf@xa,\pgf@ya) {\knot@str};
\fi
}
\pgfmathtruncatemacro{\knot@stam}{\the\value{knot@strings}-1}
\foreach \knot@sta in {1,...,\knot@stam} {
\pgfmathtruncatemacro{\knot@stap}{\knot@sta + 1}
\foreach \knot@stb in {\knot@stap,...,\the\value{knot@strings}} {
\pgfintersectionofpaths{\expandafter\pgfsetpath\csname knot@string@\knot@sta\endcsname}{\expandafter\pgfsetpath\csname knot@string@\knot@stb\endcsname}
\foreach \intsect in {1,...,\pgfintersectionsolutions} {
\pgfpointintersectionsolution{\intsect}
\pgfgetlastxy{\intsectx}{\intsecty}
\ifknot@draftmode
\node[circle,fill=white,fill opacity=.5] at (\intsectx,\intsecty) {\knot@sta-\knot@stb-\intsect};
\else
\@ifundefined{knot@crossing@\knot@sta-\knot@stb-\intsect}{
%\message{\knot@sta-\knot@stb-\intsect not defined}
}{
\pgfmathtruncatemacro{\knot@under}{\csname knot@crossing@\knot@sta-\knot@stb-\intsect\endcsname == \knot@sta ? \knot@stb : \knot@sta}
\expandafter\let\expandafter\knot@over\csname knot@crossing@\knot@sta-\knot@stb-\intsect\endcsname
\pgfscope
\clip (\intsectx,\intsecty) circle[radius=10pt];
\expandafter\expandafter\expandafter\draw\expandafter\expandafter\expandafter[\csname knot@string@opts@\knot@under\endcsname,use knot path=\csname knot@string@\knot@under\endcsname] (0,0);
\expandafter\expandafter\expandafter\draw\expandafter\expandafter\expandafter[\csname knot@string@opts@\knot@over\endcsname,use knot path=\csname knot@string@\knot@over\endcsname,white,line width=3\pgflinewidth] (0,0);
\expandafter\expandafter\expandafter\draw\expandafter\expandafter\expandafter[\csname knot@string@opts@\knot@over\endcsname,use knot path=\csname knot@string@\knot@over\endcsname] (0,0);
\endpgfscope
}
\fi
}
}
}
}
\newcommand{\strand}[1][]{%
\stepcounter{knot@strings}%
\expandafter\def\csname knot@string@opts@\the\value{knot@strings}\endcsname{#1}%
\path[save knot path=\csname knot@string@\the\value{knot@strings}\endcsname]}
\newcommand{\crossing}[2]{%
\expandafter\def\csname knot@crossing@#1\endcsname{#2}}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{knot}[knot/draft mode]
\strand[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1);
\strand[blue,ultra thick] (0,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1);
\crossing{1-2-1}{1}
\crossing{1-2-2}{2}
\crossing{1-2-3}{1}
\crossing{1-2-4}{2}
\end{knot}
\end{tikzpicture}
\begin{tikzpicture}
\begin{knot}
\strand[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1);
\strand[blue,ultra thick] (0,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1) .. controls +(1,0) and +(-1,0) .. ++(2,1) .. controls +(1,0) and +(-1,0) .. ++(2,-1);
\crossing{1-2-1}{1}
\crossing{1-2-2}{2}
\crossing{1-2-3}{1}
\crossing{1-2-4}{2}
\end{knot}
\end{tikzpicture}
\end{document}
Result (draft version on top):

Hopefully the syntax is obvious enough from the example. (It looks a lot nicer in the original PDF; the conversion to PNG is awful!). There are lots of places for improvement, but I thought I'd see if this was on the right track before polishing it.
Best Answer
When you load TikZ it loads many many macros but this is not slowing down anything per se at this time of history. It is actually not that important to load all the macros. But at the same time every library implements many TeX
if
s,dimen
s andlength
s etc. that might run out if other packages are using lots of registers. This is usually solved (or hoped to be solved) by also loading theetex
package which boosts the number of registers.Also some of the libraries change the behavior of options such as
positioning
switches thebelow of=
tobelow= of
,backgrounds
switches layering which might interfere with some patterns etc.So as a very good design decision, you turn on the rockets whenever you need them.
A nice answer by Heiko is good to keep in mind Is it possible to load a TikZ library locally?