├── .gitignore ├── README.md ├── calligraphy_doc.tex ├── examples ├── README.md ├── calligraphy_closed.tex ├── calligraphy_decorations.tex ├── calligraphy_error.tex ├── calligraphy_test.tex ├── findintersection.tex ├── knightstour.tex ├── knot-examples.tex ├── knot_pins.tex ├── knot_shading.tex ├── knots_celtic.tex ├── knots_more_celtic.tex ├── knots_small.tex ├── knots_test.tex ├── knots_triple.tex ├── knotsarrows.tex ├── localglobal.tex ├── new_prime_knots.tex ├── nfoil.tex ├── olympic.tex ├── pentagram.tex ├── prime_knots.tex ├── renderpath.tex ├── smallcrossings.tex ├── spath3_test.tex ├── spath_interface.tex ├── testpaths.tex ├── trefoil_moves.tex ├── trefoil_moves_new.tex ├── twistedpair.tex ├── twistedpair_celtic.tex └── welding.tex ├── knots_doc.tex ├── spath3.tex ├── spath3_code.dtx └── testsuite.tex /.gitignore: -------------------------------------------------------------------------------- 1 | *.pdf 2 | *.md5 3 | *.dpth 4 | *.aux 5 | *.auxlock 6 | *~ 7 | *.idx 8 | *.log 9 | *.hd 10 | *.glo 11 | *.ins 12 | *.out 13 | *.png 14 | *.tmp 15 | README.txt 16 | spath3.sty 17 | tikzlibrarycalligraphy.code.tex 18 | tikzlibraryknots.code.tex 19 | tikzlibraryspath3.code.tex 20 | CTAN/* 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `spath3` TikZ library 2 | 3 | This is a library for manipulating TikZ's _soft paths_. When TikZ reads a 4 | path construction, it first constructs a _soft path_ before converting it into 5 | an actual path in the output document. A _soft path_ contains the information 6 | needed to build the path in a TeX macro, whence it can be manipulated before 7 | it is _baked_. 8 | 9 | This library provides ways of modifying these paths before they are baked. 10 | 11 | It also provides some sub-packages which make use of this facility: 12 | 13 | 1. `knots` for drawing knot diagrams, sorting out the crossings at 14 | intersections 15 | 2. `calligraphy` which turns a path into one that might be drawn by a 16 | calligraphic pen 17 | 3. `spath3` which is a user-level interface to the core functionality 18 | 19 | # Installation 20 | 21 | These libraries are on [CTAN](https://ctan.org/pkg/spath3?lang=en) and are 22 | included in TeXLive and MikTeX. You should obtain them from one of those 23 | sources. If you know that you need the most up to date version from here, 24 | then download the file `spath3_code.dtx` and run `tex spath3_code.dtx` to generate the 25 | files. 26 | 27 | # Documentation 28 | 29 | The simplest way to get the documentation is via `texdoc` or from [CTAN](https://ctan.org/pkg/spath3?lang=en). To generate it from source, run `pdflatex` on one of the `_doc.tex` files or on `spath3.tex`. 30 | -------------------------------------------------------------------------------- /calligraphy_doc.tex: -------------------------------------------------------------------------------- 1 | \immediate\write18{tex spath3_doc.dtx} 2 | \documentclass{ltxdoc} 3 | \usepackage[T1]{fontenc} 4 | \usepackage{trace} 5 | \usepackage{lmodern} 6 | \usepackage{morefloats} 7 | \usepackage{tikz} 8 | \usetikzlibrary{decorations.pathreplacing,calligraphy,matrix} 9 | \usepackage[numbered]{hypdoc} 10 | \definecolor{lstbgcolor}{rgb}{0.9,0.9,0.9} 11 | 12 | \usepackage{listings} 13 | \lstloadlanguages{[LaTeX]TeX} 14 | \lstset{ 15 | breakatwhitespace=true, 16 | breaklines=true, 17 | language=[LaTeX]TeX, 18 | basicstyle=\small\ttfamily, 19 | keepspaces=true, 20 | columns=fullflexible 21 | } 22 | 23 | \usepackage{fancyvrb} 24 | 25 | \newenvironment{example} 26 | {\VerbatimEnvironment 27 | \begin{VerbatimOut}{example.out}} 28 | {\end{VerbatimOut} 29 | \begin{center} 30 | \setlength{\parindent}{0pt} 31 | \fbox{\begin{minipage}{.9\linewidth} 32 | \lstinputlisting[]{example.out} 33 | \end{minipage}} 34 | 35 | \fbox{\begin{minipage}{.9\linewidth} 36 | \input{example.out} 37 | \end{minipage}} 38 | \end{center} 39 | } 40 | 41 | \providecommand*{\url}{\texttt} 42 | \GetFileInfo{spath3.sty} 43 | 44 | \pdfstringdefDisableCommands{% 45 | \def\\{}% 46 | \def\url#1{<#1>}% 47 | } 48 | 49 | \title{The \textsf{calligraphy} Package: Documentation} 50 | \author{Andrew Stacey \\ \url{loopspace@mathforge.org}} 51 | \date{\fileversion~from \filedate} 52 | 53 | \begin{document} 54 | 55 | \maketitle 56 | 57 | \section{Pre-Introduction} 58 | This library is built on top of a package for manipulating PGF's \emph{soft paths} called \texttt{spath3}. 59 | Version 2.0 of \texttt{spath3} involved considerable reorganisation of the code. 60 | I tried to ensure that this didn't affect this library but it is extremely likely that I wasn't fully successful. 61 | If something that used to work no longer does, please do let me know either by opening an issue on github (\url{https://github.com/loopspace/spath3}) or at the above email. 62 | 63 | \section{Introduction} 64 | The \Verb+calligraphy+ TikZ library is designed to enable calligraphic style drawings in TikZ. 65 | The idea is to be able to ``stroke'' a line with a ``pen''. 66 | As a simple example, compare the two lines in the following picture. 67 | 68 | \begin{example} 69 | \begin{center} 70 | \begin{tikzpicture} 71 | \pen (-135:.25) -- (45:.25); 72 | \draw[line width=.5cm] (0,0) .. controls +(45:1) and +(-135:1) .. ++(3,0); 73 | \calligraphy (0,-1) .. controls +(45:1) and +(-135:1) .. ++(3,0); 74 | \end{tikzpicture} 75 | \end{center} 76 | \end{example} 77 | 78 | The paths are identical in definition but the first is drawn using the standard TikZ path with a line width of .5cm. 79 | The second is ``stroked'' with a calligraphic pen of width .5cm angled at 45 degrees. 80 | \section{How It Works} 81 | To know how to use this library, it is worth knowing a little about how it works. 82 | A ``pen'' is a path, as is the line that is the template for the pen stroke. 83 | The two paths are joined together to form a region which is filled. 84 | Thus in constructing the example given in the introduction, the following path is built. 85 | \begin{center} 86 | \begin{tikzpicture} 87 | \draw (0,-1) .. controls +(45:1) and +(-135:1) .. node (op) {} ++(3,0) -- node (pp) {} ++(45:.5) .. controls +(-135:1) and +(45:1) .. node (opr) {} ++(-3,0) -- node (ppr) {} (0,-1); 88 | \draw[<-] (op) -- ++(0,-.5) node[anchor=north] {original path}; 89 | \draw[<-] (pp) -- ++(.5,0) node[anchor=west] {pen path}; 90 | \draw[<-] (opr) -- ++(0,.5) node[anchor=south] {original path reversed}; 91 | \draw[<-] (ppr) -- ++(-.5,0) node[anchor=east] {pen path reversed}; 92 | \end{tikzpicture} 93 | \end{center} 94 | What is important to note about this is that the ``pen'' isn't \emph{actually} dragged along the path, it is merely a simulation. 95 | This can be shown with the following simple example. 96 | The first is a continuous path that goes past the angle of the pen and thus the upstroke would involve pushing the pen. 97 | The second is how it is meant to be done, the second line is drawn from top to bottom. 98 | However, as the direction of the path isn't important, the same effect can be obtained by ``lifting the nib'' between the lines. 99 | \begin{example} 100 | \begin{center} 101 | \begin{tikzpicture} 102 | \pen (-135:.125) -- (45:.125); 103 | \calligraphy (0,0) -- (1,0) -- (1,1); 104 | \calligraphy (2,0) -- (3,0) (3,1) -- (3,0); 105 | \calligraphy (4,0) -- (5,0) +(0,0) -- (5,1); 106 | \end{tikzpicture} 107 | \end{center} 108 | \end{example} 109 | It should work as expected providing the following golden rule is not violated: 110 | \begin{quotation} 111 | Never \emph{push} a calligraphic pen. 112 | \end{quotation} 113 | This is good advice for ordinary calligraphy as well, so a path that is realisable as an honest calligraphic path should be fine with this library. 114 | Actually since, as remarked above, the direction of the path isn't important, a more accurate golden rule would be that one should never swap from pushing to pulling or vice versa without lifting the pen off the paper; but that isn't as succinct. 115 | The paths for both pens and templates can be reasonably complicated. 116 | They can contain gaps, but should not contain closed paths, nor rectangles. 117 | The implementation works by breaking a path into its constituent pieces (broken up by ``move to''s) and working bit by bit. 118 | \begin{example} 119 | \begin{center} 120 | \begin{tikzpicture} 121 | \pen (-135:.25) -- (-135:.125) (45:.125) -- (45:.25); 122 | \calligraphy (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-4) (0,-4) .. controls +(45:1) and +(-135:1) .. +(3,0); 123 | \end{tikzpicture} 124 | \end{center} 125 | \end{example} 126 | \section{Copperplate} 127 | Copperplate pens are somewhat special. 128 | They are ``thin'' so don't need the same treatment as a ``thick'' pen, but one should be able to vary the pressure with a copperplate pen to get a variation of thickness. 129 | Specifying a copperplate pen is straightforward: it is a pen with no thickness. 130 | \begin{example} 131 | \begin{center} 132 | \begin{tikzpicture}[line width=2pt] 133 | \pen (0,0); 134 | \calligraphy[heavy] (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 135 | \calligraphy[light] (4,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (4,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 136 | \end{tikzpicture} 137 | \end{center} 138 | \end{example} 139 | With a copperplate pen, the segments of a path are tapered. 140 | Copperplate and normal pens can be mixed. 141 | Any part of the pen specification that has no length is treated as a copperplate pen. 142 | \begin{example} 143 | \begin{center} 144 | \begin{tikzpicture}[line width=1pt] 145 | \pen (-135:.125) -- (0,0) (45:.125); 146 | \calligraphy (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 147 | \end{tikzpicture} 148 | \end{center} 149 | \end{example} 150 | %% \section{Annotations} 151 | %% As an addition, calligraphic paths can be annotated to show how they were constructed. 152 | %% A path with an arrow is drawn at a set offset from the last part of the path. 153 | %% \begin{example} 154 | %% \begin{center} 155 | %% \begin{tikzpicture}[line width=1pt] 156 | %% \pen (-135:.125) -- (0,0) (45:.125); 157 | %% \calligraphy[annotate] (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 158 | %% \end{tikzpicture} 159 | %% \end{center} 160 | %% \end{example} 161 | \section{Style Options} 162 | There are plenty of options for styling the paths and pens. 163 | \subsection{Definition Options} 164 | Internally, making a pen is a two-step process. 165 | First a pen has to be \emph{defined} and then \emph{processed}. 166 | To define a pen, the user has to specify a path. 167 | That path is stored in a global macro and so can be accessed in throughout the document. 168 | However, before being used, the pen has to be processed. 169 | At this stage, the pen is converted from a macro in to a special object. 170 | These special objects are local and cannot (at present) be made global. 171 | Thus whilst a pen can be \emph{defined} inside a group, the \emph{processing} stage has to happen in the outermost group in which the pen is going to be used. 172 | There is a shortcut command that (via a bit of suspicious hackery) does all this within a \Verb+tikzpicture+ group. 173 | However, if a pen is to be used in several different pictures, it must be processed outside the group in which it is defined. 174 | The following macros and keys are used to set up and use a pen. 175 | %All the keys are in the \Verb+/pgf/calligraphy+ family. 176 | \begin{itemize} 177 | \item \DescribeMacro{define pen}If the \Verb+define pen+ key is specified on a path then that path will be used to define a pen. 178 | It can take one option which will be the pen name, if not specified then \Verb+default+ is assumed. 179 | The resulting path will not be counted for bounding box considerations. 180 | When the pen is used, the origin will correspond to the path along which it is dragged. 181 | \item \DescribeMacro{pen name}The key \Verb+pen name=name+ sets the name for the current pen. 182 | This can be used either when defining or using a pen. 183 | \item \DescribeMacro{\pen}\DescribeMacro{\definepen}The macros \Verb+\pen+ and \Verb+\definepen+ are analogous to the TikZ commands \Verb+\draw+ or \Verb+\fill+ in that they act like a path command but store the path as a pen. 184 | The difference between them is that \Verb+\definepen+ is to be used outside a TikZ picture (it contains its own \Verb+\tikz+ command) and \Verb+\pen+ inside. 185 | %% These macros also change the ``key family'' to \Verb+/pgf/calligraphy+ so that any further options do not need their full path. 186 | %% \item \DescribeMacro{\processpen}The macro \Verb+\processpen+ processes a pen so that it is set up for using later on. 187 | %% As remarked earlier, it has to be given at least at the outermost grouping of where it will be used. 188 | %% It takes an optional argument which is the pen name. 189 | %% This is only needed if the pen will be used in a group other than the one in which it is defined (or if the hackery that means this isn't needed with the \Verb+\pen+ command fails for some unknown reason). 190 | \item \DescribeMacro{use pen}The key \Verb+use pen=name+ on a path means that that path should be ``stroked'' with the pen (\Verb+default+ if no name is given, or none specified via the \Verb+pen name+ key). 191 | %% \item \DescribeMacro{\calligraphy}The macro \Verb+\calligraphy+ is a shortcut for specifying a path with the key \Verb+use pen+ already set. 192 | %% This macro also changes the ``key family'' to \Verb+/pgf/calligraphy+ so that any further options do not need their full path. 193 | \end{itemize} 194 | \subsection{Style Options} 195 | There are various options available for styling the calligraphic paths. 196 | %% All of these are in the \Verb+/pgf/calligraphy+ key family, but the \Verb+\calligraphy+ command automatically switches to that family so the key path is not needed. 197 | %% Any unknown keys are processed as follows: 198 | %% \begin{enumerate} 199 | %% \item A check is made to see if a pen of that name has been defined. 200 | %% If so, that pen is used. 201 | %% This is similar to the \Verb+\node[shape]+ syntax 202 | %% \item A check is made to see if the unknown key corresponds to a colour. 203 | %% If so, that colour is installed as the pen colour. 204 | %% This is similar to the colour handling of TikZ paths. 205 | %% (In fact, it uses the same code.) 206 | %% \item All other unknown options are passed on to TikZ. 207 | %% \end{enumerate} 208 | The style options are as follows. 209 | \begin{itemize} 210 | \item \DescribeMacro{pen colour}The \Verb+pen colour+ style defines the default colour to be used. 211 | Since calligraphic paths are sometimes filled and sometimes stroked, this ensures that the colour is used correctly. 212 | \item \DescribeMacro{nib style}It is possible to style particular ``nibs'' (i.e., segments of the pen path) separately. 213 | This is the \Verb+nib style+ option, which takes two arguments. 214 | The first is the index of the part of the nib and the second is the style options to be applied. 215 | \item \DescribeMacro{stroke style}It is also possible to style particular parts of the template path. 216 | One way to do this is to use the \Verb+stroke style+ key, which takes two arguments. 217 | The first is the index of the part of the stroke and the second is the style options to be applied. 218 | \item \DescribeMacro{this stroke style}It is also possible to style particular parts of the template path as the path is constructed. 219 | This is done by putting \Verb+[this stroke style={}]+ in the template path at the relevant part. 220 | The style is saved and applied to that segment of the template path. 221 | \item \DescribeMacro{taper}The tapering of copperplate paths can be controled by the \Verb+taper+ option. 222 | It takes arguments \Verb+none+, \Verb+both+, \Verb+start+, and \Verb+end+. 223 | \item \DescribeMacro{weight}\DescribeMacro{heavy}\DescribeMacro{light}Copperplate paths come in two ``weights'': \emph{heavy} and \emph{light}. 224 | The weight also affects the tapering: by default a light path is tapered to nothing whilst a heavy path is tapered to the width of a light path. 225 | Weights can be specified by either \Verb+weight=weight+ or just \Verb+heavy+ and \Verb+light+. 226 | It is possible to change the weight for different components of a path using the \Verb+stroke style+ key. 227 | With tapering, this means that one can easily vary from a light stroke to a heavy one. 228 | The relevant widths are controlled by the keys \DescribeMacro{heavy line width}\Verb+heavy line width+ and the \DescribeMacro{light line width}\Verb+light line width+. 229 | The \DescribeMacro{taper line width}\Verb+taper line width+, is set automatically by the weight but can be altered afterwards using the \Verb+taper line width+ key. 230 | %% \item \DescribeMacro{annotate}The key \Verb+annotate+ switches on annotations. 231 | %% The style of the annotations is controlled by the keys \DescribeMacro{annotation style}\Verb+annotation style+, \DescribeMacro{annotation shift}\Verb+annotation shift+ which controls how the annotation path is shifted from the final component of the calligraphic path, \DescribeMacro{annotation nodes style}\Verb+annotation nodes style+ for global style of the nodes, \DescribeMacro{annotation node style}\Verb+annotation node style+ for styling of particular nodes. 232 | %% This latter takes two options: the node number and the style to be applied. 233 | %% The annotation path and annotation node styles take ordinary TikZ styling options. 234 | \end{itemize} 235 | \begin{example} 236 | \begin{center} 237 | \begin{tikzpicture} 238 | \calligraphy[pen colour=green,nib style={2}{color=red}] (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 239 | \calligraphy[line width=1pt] (0,-4) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-7) .. controls +(45:1) and +(-135:1) .. +(3,0); 240 | \end{tikzpicture} 241 | \end{center} 242 | \end{example} 243 | \section{Decorations} 244 | If a TikZ/PGF decorations library is loaded prior to this library, then the \Verb+calligraphy+ library defines some decorations that use the calligraphic paths, specifically with the copperplate nib. 245 | The current decorations are: 246 | \begin{itemize} 247 | \item \DescribeMacro{calligraphic brace}\Verb+calligraphic brace+ for a brace. 248 | \item \DescribeMacro{calligraphic straight parenthesis}\Verb+calligraphic straight parenthesis+ for a parenthesis with straight middle component. 249 | \item \DescribeMacro{calligraphic curved parenthesis}\Verb+calligraphic curved parenthesis+ for a parenthesis with a curved middle component. 250 | \end{itemize} 251 | All the above use the \Verb+amplitude+ option to specify their size. 252 | The following is an example of their use, together with the standard \Verb+brace+ and the \Verb+delimiter+ key from the \Verb+matrix+ library for comparison. 253 | \begin{example} 254 | \begin{center} 255 | \begin{tikzpicture} 256 | \draw[decorate,decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) -- (0,8); 257 | \draw[line width=2pt,decorate,decoration={brace,amplitude=10},line cap=round] (1,0) -- ++(0,8); 258 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=\{] (a) at (2,0) {}; 259 | \draw[decorate,decoration={calligraphic straight parenthesis,amplitude=4mm},ultra thick] (3,0) -- ++(0,8); 260 | \draw[decorate,decoration={calligraphic curved parenthesis,amplitude=4mm},ultra thick] (4,0) -- ++(0,8); 261 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=(] (a) at (5,0) {}; 262 | \end{tikzpicture} 263 | \end{center} 264 | \end{example} 265 | \section{Pre-Defined Pens} 266 | The following pens are predefined: 267 | \begin{itemize} 268 | \item \DescribeMacro{copperplate}\Verb+copperplate+: 269 | \begin{example} 270 | \begin{center} 271 | \tikz \calligraphy[copperplate] (0,0) .. controls +(1,-1) and +(-1,1) .. ++(3,0) [this stroke style={light,taper=start}] +(0,0) .. controls +(1,-1) and +(-1,1) .. ++(3,0) [this stroke style={heavy}] +(0,0) .. controls +(1,-1) and +(-1,1) .. ++(3,0) [this stroke style={light,taper=end}]; 272 | \end{center} 273 | \end{example} 274 | \end{itemize} 275 | 276 | \end{document} 277 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples for the spath3 library 2 | 3 | Most of the examples contain a couple of lines at the start to regenerate the package files from the `spath3_code.dtx` file so that I don't have to keep remembering to regenerate them when testing a feature using an example file. 4 | If the example starts with something like: 5 | 6 | ``` 7 | \RequirePackage{shellesc} 8 | \immediate\write18{cd ..; tex spath3_code.dtx} 9 | ``` 10 | 11 | then remove or comment out these lines. 12 | 13 | ## Current examples 14 | 15 | These are examples that ought to work with the current version of the library. 16 | 17 | * calligraphy_closed.tex 18 | 19 | Testing how the calligraphy package works with closed paths. 20 | 21 | * calligraphy_decorations.tex 22 | 23 | Tests the decorations part of the calligraphy library. 24 | 25 | * calligraphy_test.tex 26 | 27 | This is the main test suite for the calligraphy library. 28 | 29 | * knightstour.tex 30 | 31 | Primarily an example of SVG export, but also demonstrates how to use paths piecemeal when working with the full path causes TeX to complain. 32 | 33 | * knot-examples.tex 34 | 35 | Some examples of knot and link diagrams that show some of the features of the knot library. 36 | 37 | * knots_test.tex 38 | 39 | Key test file for knots with lots of examples. 40 | 41 | * localglobal.tex 42 | 43 | Basic knot to test if I'm doing the local/global assignments correctly. 44 | 45 | * new_prime_knots.tex 46 | 47 | Prime knots up to 7-7 using the `spath3` TikZ library. 48 | 49 | * prime_knots.tex 50 | 51 | Prime knots up to 7-7 using the `knots` TikZ library. 52 | 53 | * spath3_test.tex 54 | 55 | Main test file for the `spath3` library. 56 | 57 | * spath_interface.tex 58 | 59 | Testing welding soft paths together. 60 | 61 | * testpaths.tex 62 | 63 | Defines the paths used in the test suite in the main directory. 64 | 65 | * trefoil_moves_new.tex 66 | 67 | Showing how to deform one view of a trefoil into another, using the `spath3` library. 68 | 69 | * trefoil_moves.tex 70 | 71 | Showing how to deform one view of a trefoil into another, using the `knots` library. 72 | 73 | 74 | ## Examples from TeX-SX 75 | 76 | Quite a few of the examples come from questions on TeX-SX. 77 | 78 | * knot_pins.tex 79 | 80 | Testing label styles for knots. 81 | 82 | * knotsarrows.tex 83 | 84 | Various ways of decorating a strand within a knot environment. 85 | 86 | * knots_celtic.tex 87 | 88 | Demonstrating how to get rid of the artefacts formed by using the double style to render celtic knots. 89 | 90 | * knot_shading.tex 91 | 92 | Filling the middle of a knot. 93 | 94 | * knots_more_celtic.tex 95 | 96 | A more complicated celtic knot (this was en route to the [`celtic`](https://github.com/loopspace/celtic) package). 97 | 98 | * knots_small.tex 99 | 100 | Everyone on TeX-SX likes drawing knots small, it seems. 101 | 102 | * knots_triple.tex 103 | 104 | Testing triple intersections. 105 | 106 | * nfoil.tex 107 | 108 | Code for an n-foil knot. 109 | 110 | * olympic.tex 111 | 112 | Linked olympic rings. 113 | 114 | * smallcrossings.tex 115 | 116 | Crossings close together strike again. 117 | 118 | * twistedpair_celtic.tex 119 | 120 | Another example from TeX-SX 121 | 122 | * twistedpair.tex 123 | 124 | Different version of the above 125 | 126 | 127 | ## Old Examples 128 | 129 | These are examples that I haven't kept up to date with the latest version of the code. 130 | Generally, they are ones that I've used to test out some feature or figure out some bug and which once that's tested or figured out then I've not updated them since. 131 | I find them useful to look back on for ideas so I keep them. 132 | 133 | * calligraphy_error.tex 134 | 135 | The file name suggests this was to test an error. I don't recall what that was. 136 | 137 | * findintersection.tex 138 | 139 | Testing some early ideas on splitting paths at intersection points. The ideas persisted, but the syntax didn't. 140 | 141 | * pentagram.tex 142 | 143 | Yet another knot diagram, showing artefacts from the double effect. 144 | 145 | * renderpath.tex 146 | 147 | Testing saving and restoring a soft path with old syntax. 148 | 149 | * welding.tex 150 | 151 | Welding two paths together -------------------------------------------------------------------------------- /examples/calligraphy_closed.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | 4 | \documentclass{article} 5 | 6 | \usepackage{tikz} 7 | \usetikzlibrary{calligraphy,spath3} 8 | 9 | \begin{document} 10 | 11 | 12 | 13 | \begin{tikzpicture} 14 | \pen (-150:.25) -- (30:.25); 15 | \calligraphy (1,0) (2,0) -- (0,2); 16 | \draw[red] (0,1) -- (0,0) -- (1,0); 17 | \end{tikzpicture} 18 | 19 | \vspace*{1cm} 20 | 21 | \begin{tikzpicture} 22 | \calligraphy (0,3) arc(0:360:1) -- cycle; 23 | \calligraphy (3,0) circle(1); 24 | \calligraphy (0,-1) (1,-1) -- (2,-1) (3,-1) -- (4,-1); 25 | \end{tikzpicture} 26 | 27 | 28 | \begin{tikzpicture} 29 | \calligraphy[copperplate] (0,0) circle[radius=1]; 30 | \calligraphy[copperplate] (4,0) arc[start angle=0, end angle=360, radius=1] -- cycle; 31 | \begin{scope}[xshift=6cm] 32 | \calligraphy[copperplate] (0:1) arc(0:360:1) -- cycle; 33 | \end{scope} 34 | 35 | \end{tikzpicture} 36 | 37 | \begin{tikzpicture} 38 | \calligraphy (0,0) circle[radius=1]; 39 | \calligraphy (4,0) arc[start angle=0, end angle=360, radius=1] -- cycle; 40 | \begin{scope}[xshift=6cm] 41 | \calligraphy (0:1) arc(0:360:1) -- cycle; 42 | \end{scope} 43 | 44 | \end{tikzpicture} 45 | 46 | \end{document} 47 | -------------------------------------------------------------------------------- /examples/calligraphy_decorations.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | %\documentclass[convert={size=400},border=10]{standalone} 3 | \usepackage{tikz} 4 | \usetikzlibrary{decorations.pathreplacing,matrix,calligraphy} 5 | 6 | 7 | \begin{document} 8 | \begin{tikzpicture} 9 | \draw[red,postaction={decorate,black},decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) .. controls +(1,1) and +(1,-1) .. (0,8); 10 | \end{tikzpicture} 11 | 12 | \begin{tikzpicture} 13 | \draw[red,postaction={decorate,black},decoration={brace,amplitude=4mm},ultra thick] (0,0) .. controls +(1,1) and +(1,-1) .. (0,8); 14 | \end{tikzpicture} 15 | 16 | 17 | \begin{tikzpicture} 18 | \draw[decorate,decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) -- (0,8); 19 | \draw[line width=2pt,decorate,decoration={brace,amplitude=10},line cap=round] (1,0) -- ++(0,8); 20 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=\{] (a) at (2,0) {}; 21 | \draw[decorate,decoration={calligraphic straight parenthesis,amplitude=4mm},ultra thick] (3,0) -- ++(0,8); 22 | \draw[decorate,decoration={calligraphic curved parenthesis,amplitude=4mm},ultra thick] (4,0) -- ++(0,8); 23 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=(] (a) at (5,0) {}; 24 | \end{tikzpicture} 25 | \end{document} 26 | -------------------------------------------------------------------------------- /examples/calligraphy_error.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{tikz} 4 | 5 | \usetikzlibrary{decorations.pathreplacing,calligraphy} 6 | 7 | \begin{document} 8 | 9 | \tikz\draw[decorate,decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) -- (0,8); 10 | 11 | \end{document} -------------------------------------------------------------------------------- /examples/calligraphy_test.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | \documentclass{article} 4 | \RequirePackage[enable-debug]{expl3} 5 | \ExplSyntaxOn 6 | \debug_on:n {check-declarations, deprecation} 7 | \ExplSyntaxOff 8 | %\documentclass[convert={size=400},border=10]{standalone} 9 | \usepackage{tikz} 10 | \usetikzlibrary{decorations.pathreplacing,matrix,calligraphy} 11 | 12 | 13 | \begin{document} 14 | 15 | \begin{tikzpicture} 16 | \pen (-150:.15) -- (30:.15); 17 | \calligraphy[copperplate] 18 | (0,0) .. controls +(1,.5) and +(-1,-.5) .. (2,0); 19 | \draw[yshift=-.5cm] (0,0) .. controls +(1,.5) and +(-1,-.5) .. (2,0) .. controls +(1,.5) and +(-1,-.5) .. (4,0); 20 | \calligraphy[ 21 | yshift=-1cm, 22 | copperplate 23 | ] (0,0) .. controls +(1,.5) and +(-1,-.5) .. (2,0) .. controls +(1,.5) and +(-1,-.5) .. (4,0); 24 | \end{tikzpicture} 25 | 26 | 27 | \begin{tikzpicture}[scale=2] 28 | \calligraphy[ 29 | copperplate, 30 | heavy line width=8pt, 31 | light line width=4pt, 32 | weight=heavy, 33 | annotate={draw,thick,red,->,shorten >=1ex,shorten <=1ex}, 34 | annotation shift={(1em,1em)}, 35 | annotation node style={1}{fill=white,fill opacity=.5,circle,text opacity=1,anchor=south west}, 36 | annotation node style={2}{fill=white,fill opacity=.5,circle,text opacity=1,anchor=south west}, 37 | annotation node style={3}{fill=white,fill opacity=.5,circle,text opacity=1,anchor=south}, 38 | ] 39 | (-.5,1.2) -- (-.5,-.3) .. controls +(60:.4) and +(120:.4) .. (.7,-.3) 40 | (-.5,1.2) .. controls +(-60:.4) and +(-120:.4) .. (.7,1.2) -- (.7,-1.35) +(0,0) .. controls +(120:1) and +(140:1.5) .. (-.9,-1.7) 41 | ; 42 | \end{tikzpicture} 43 | 44 | \begin{tikzpicture} 45 | \draw[decorate,decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) -- (0,8); 46 | \draw[line width=2pt,decorate,decoration={brace,amplitude=10},line cap=round] (1,0) -- ++(0,8); 47 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=\{] (a) at (2,0) {}; 48 | \draw[decorate,decoration={calligraphic straight parenthesis,amplitude=4mm},ultra thick] (3,0) -- ++(0,8); 49 | \draw[decorate,decoration={calligraphic curved parenthesis,amplitude=4mm},ultra thick] (4,0) -- ++(0,8); 50 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=(] (a) at (5,0) {}; 51 | \end{tikzpicture} 52 | 53 | \begin{tikzpicture}[line width=2pt] 54 | \pen (0,0) -- ++(.5,.5) ++(.5,.5); 55 | \end{tikzpicture} 56 | 57 | 58 | \begin{tikzpicture} 59 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=(] at (0,0) {}; 60 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=\{] at (.3,0) {}; 61 | \draw[pen colour=red,decorate,decoration={calligraphic straight parenthesis,amplitude=1.5mm},thick] (.6,0) -- ++(0,8); 62 | \draw[pen colour=red,decorate,decoration={calligraphic curved parenthesis,amplitude=1.5mm},thick] (1,0) -- ++(0,8); 63 | \draw (.85,4) circle[radius=2pt]; 64 | \draw[gray,opacity=.5] (-.06,0) rectangle ++(-.15,.5); 65 | \draw[gray,opacity=.5] (-.07,0) -- ++(130:1); 66 | \draw[gray,opacity=.5] (-.07,0) -- ++(-.15,.5); 67 | \calligraphy[copperplate,light,taper width=.5\pgflinewidth] (.1,0) .. controls +(130:.15) and +(0,-.15) .. ++(-.15,.5) -- ++(0,7) .. controls +(0,.15) and +(230:.15) .. ++(.15,.5); 68 | \draw[gray,opacity=.5] (1,0) -- ++(-.15,.5); 69 | \end{tikzpicture} 70 | 71 | \begin{tikzpicture} 72 | \pen[pen name=cplate] (0,0); 73 | \calligraphy[pen name=cplate,red] (0,0) .. controls +(1,1) and +(-1,-1) .. ++(5,0); 74 | \end{tikzpicture} 75 | 76 | \begin{tikzpicture} 77 | \draw[decorate,decoration={calligraphic brace,amplitude=4mm},ultra thick] (0,0) -- (0,8); 78 | \draw[decorate,decoration={calligraphic straight parenthesis,amplitude=4mm},ultra thick] (3,0) -- ++(0,8); 79 | \draw[decorate,decoration={calligraphic curved parenthesis,amplitude=4mm},ultra thick] (4,0) -- ++(0,8); 80 | \draw[line width=2pt,decorate,decoration={brace,amplitude=10},line cap=round] (1,0) -- ++(0,8); 81 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=\{] (a) at (2,0) {}; 82 | \node[anchor=south west,minimum height=8cm,outer sep=0pt,left delimiter=(] (a) at (5,0) {}; 83 | \end{tikzpicture} 84 | 85 | \begin{tikzpicture} 86 | \calligraphy[heavy,pen colour=red,nib style={1}{pen colour=green}] (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) [this stroke style={light,nib style={1}{pen colour=yellow}}] ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) [this stroke style={heavy}] (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0) [this stroke style={light}]; 87 | \end{tikzpicture} 88 | 89 | \begin{tikzpicture} 90 | \pen (0,0); 91 | \tikzset{heavy line width=3mm} 92 | \calligraphy[heavy, taper=end] (0,0) -- +(10,0); 93 | \calligraphy[heavy, taper=start] (0,-1) -- +(10,0); 94 | \end{tikzpicture} 95 | 96 | 97 | \begin{tikzpicture} 98 | \pen (-135:.25) -- (45:.25); 99 | \draw[line width=.5cm] (0,0) .. controls +(45:1) and +(-135:1) .. ++(3,0); 100 | \calligraphy (0,-1) .. controls +(45:1) and +(-135:1) .. ++(3,0); 101 | \end{tikzpicture} 102 | 103 | \begin{tikzpicture}[line width=2pt] 104 | \pen (0,0); 105 | \calligraphy[heavy,taper=end] (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 106 | \calligraphy[light] (4,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (4,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 107 | \end{tikzpicture} 108 | 109 | \begin{tikzpicture}[line width=1pt] 110 | \pen (-135:.125) -- (0,0) (45:.125); 111 | \calligraphy (0,0) .. controls +(45:1) and +(-135:1) .. +(3,0) ++(1.5,0) .. controls +(-135:2) and +(45:2) .. +(0,-3) (0,-3) .. controls +(45:1) and +(-135:1) .. +(3,0); 112 | \end{tikzpicture} 113 | 114 | \begin{tikzpicture}[thick] 115 | %\pen (0,0); 116 | \coordinate (a) at (0,.5); 117 | \coordinate (b) at (.5,0); 118 | \coordinate (c) at (0,-.5); 119 | \coordinate (d) at (-.5,0); 120 | \draw (d) to[bend left] (c) to[out=150,in=210] (c); 121 | \end{tikzpicture} 122 | 123 | 124 | 125 | \begin{tikzpicture} 126 | \pen (-150:.25) -- (30:.25); 127 | \calligraphy (1,0) (2,0) -- (0,2); 128 | \draw[red] (0,1) -- (0,0) -- (1,0); 129 | \end{tikzpicture} 130 | 131 | \vspace*{1cm} 132 | 133 | \begin{tikzpicture} 134 | \draw (0,3) arc(0:360:1) -- cycle; 135 | \draw (3,0) circle(1); 136 | \calligraphy (0,-1) (1,-1) -- (2,-1) (3,-1) -- (4,-1); 137 | \end{tikzpicture} 138 | 139 | 140 | \begin{tikzpicture} 141 | \calligraphy[copperplate] (0,0) circle[radius=1]; 142 | \calligraphy[copperplate] (4,0) arc[start angle=0, end angle=360, radius=1] -- cycle; 143 | \begin{scope}[xshift=6cm] 144 | \calligraphy[copperplate] (0:1) arc(0:360:1) -- cycle; 145 | \end{scope} 146 | 147 | \end{tikzpicture} 148 | 149 | \begin{tikzpicture} 150 | \draw (0,0) circle[radius=1]; 151 | \draw (4,0) arc[start angle=0, end angle=360, radius=1] -- cycle; 152 | \begin{scope}[xshift=6cm] 153 | \draw (0:1) arc(0:360:1) -- cycle; 154 | \end{scope} 155 | 156 | \end{tikzpicture} 157 | 158 | \end{document} 159 | 160 | % Local Variables: 161 | % tex-output-type: "pdf18" 162 | % End: 163 | -------------------------------------------------------------------------------- /examples/findintersection.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3.dtx} 3 | \documentclass{article} 4 | 5 | \usepackage{xparse} 6 | \usepackage{tikz} 7 | \usetikzlibrary{spath3,intersections,hobby,patterns} 8 | 9 | \begin{document} 10 | 11 | \begin{tikzpicture}[use Hobby shortcut] 12 | 13 | \shade[left color=cyan, right color=magenta, shading angle=90] (-.5,-.2) rectangle (7.5,2.2); 14 | \fill[pattern=bricks, pattern color=white] (-.5,-.2) rectangle (7.5,2.2); 15 | 16 | \path 17 | [ 18 | split current path at self intersections={coil}{1111111111111111111111} 19 | ] ([out angle=0]0,0) 20 | .. +(.85,1) .. +(.25,2) .. +(-.35,1) .. ++(.5,0) 21 | .. +(.85,1) .. +(.25,2) .. +(-.35,1) .. ++(.5,0) 22 | .. +(.85,1) .. +(.25,2) .. +(-.35,1) .. ++([in angle=180].5,0) 23 | ; 24 | 25 | \foreach \k in {1,..., \spathselfintersectioncount} { 26 | \tikzset{shorten spath at both ends={coil \k}{2pt}, globalise spath=coil \k} 27 | } 28 | 29 | \foreach \k in {1,..., 4} { 30 | \draw[restore spath=coil \k]; 31 | } 32 | 33 | \foreach[evaluate=\l as \xshift using \l*.5cm] \l in {0,...,10} { 34 | \foreach \k in {5,..., 9} { 35 | \draw[translate spath={coil \k}{\xshift pt}{0pt},restore spath=coil \k]; 36 | } 37 | } 38 | 39 | \draw[translate spath={coil 10}{5cm}{0pt},restore spath=coil 10]; 40 | 41 | \end{tikzpicture} 42 | %\end{document} 43 | 44 | \begin{tikzpicture} 45 | \draw[line width=3pt, blue!50!white, save spath=shortening] (0,0) .. controls +(1,1) and +(-1,-1) .. (2,0); 46 | 47 | \draw (2,0) circle[radius=10pt] circle[radius=5pt]; 48 | 49 | \foreach \k in {0,...,10} { 50 | \tikzset{shorten spath at end={shortening}{\k*5pt}} 51 | \draw[-|,restore spath=shortening]; 52 | } 53 | 54 | \tikzset{translate spath={shortening}{0pt}{-1cm}} 55 | \draw[line width=3pt, green!50!white, restore spath=shortening]; 56 | 57 | \draw (2,-1) circle[radius=10pt] circle[radius=5pt]; 58 | 59 | 60 | \draw[-|,restore spath=shortening]; 61 | 62 | \foreach \k in {0,...,10} { 63 | \tikzset{shorten spath at end={shortening}{5pt},globalise spath={shortening}} 64 | \draw[-|,restore spath=shortening]; 65 | } 66 | 67 | 68 | \end{tikzpicture} 69 | %\end{document} 70 | 71 | \begin{tikzpicture} 72 | 73 | \shade[left color=cyan, right color=magenta] (-.2,-2.2) rectangle (2.2,4.2); 74 | 75 | 76 | \path[save spath=a] (0,-2) -- (0,0) to[out=90, in=-90] (2,2) -- (2,4); 77 | \path[save spath=b] (2,-2) -- (0,4); 78 | 79 | \tikzset{ 80 | split at intersections={a}{b}{a}{b}{} 81 | } 82 | 83 | \path[restore spath=a 1] coordinate (a); 84 | \draw (a) circle[radius=5pt]; 85 | \tikzset{shorten spath at end={a 1}{5pt}}; 86 | \tikzset{shorten spath at start={a 2}{5pt}}; 87 | \draw[line width=1pt,red,restore spath=a 1]; 88 | \draw[line width=1pt,blue,restore spath=a 2]; 89 | \draw[line width=1pt,green!50!black, restore spath=b]; 90 | \end{tikzpicture} 91 | 92 | \begin{tikzpicture}[ 93 | use Hobby shortcut, 94 | ] 95 | 96 | \fill[red!50!white] (-3,3) rectangle (3,-3); 97 | \fill[pattern=bricks, pattern color=white] (-3,3) rectangle (3,-3); 98 | 99 | \path 100 | [ 101 | split current path at self intersections={trefoil}{121} 102 | ] 103 | ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) }; 104 | 105 | \foreach \k in {1,..., \spathselfintersectioncount} { 106 | \tikzset{shorten spath at both ends={trefoil \k}{5pt}} 107 | \draw[line width=\k pt, restore spath=trefoil \k]; 108 | } 109 | 110 | \end{tikzpicture} 111 | 112 | \begin{tikzpicture}[ 113 | use Hobby shortcut, 114 | ] 115 | 116 | \fill[red!50!white] (-.5,-.5) rectangle (8.5,1.5); 117 | \fill[pattern=bricks, pattern color=white] (-.5,-.5) rectangle (8.5,1.5); 118 | 119 | \path[save spath=pathA] (0,0) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1); 120 | \path[save spath=pathB] (0,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1); 121 | 122 | \tikzset{split at intersections={pathA}{pathB}{pathA}{pathB}{1212}} 123 | 124 | \foreach \k in {1,..., \spathfirstintersectioncount} { 125 | \tikzset{shorten spath at both ends={pathA \k}{5pt}} 126 | \draw[green!50!black, ultra thick, restore spath=pathA \k]; 127 | } 128 | 129 | \foreach \k in {1,..., \spathsecondintersectioncount} { 130 | \tikzset{shorten spath at both ends={pathB \k}{5pt}} 131 | \draw[blue, ultra thick, restore spath=pathB \k]; 132 | } 133 | 134 | \end{tikzpicture} 135 | 136 | 137 | \end{document} 138 | -------------------------------------------------------------------------------- /examples/knightstour.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | \documentclass{article} 4 | 5 | \usepackage{tikz} 6 | \usetikzlibrary{spath3,intersections} 7 | 8 | \begin{document} 9 | 10 | \begin{tikzpicture} 11 | 12 | \fill[gray] 13 | (0,0) rectangle +(2,2) 14 | (2,2) rectangle +(2,2) 15 | (4,4) rectangle +(2,2) 16 | (0,4) rectangle +(2,2) 17 | (4,0) rectangle +(2,2) 18 | ; 19 | \draw (0,0) grid[step=2] (6,6); 20 | 21 | \path[ 22 | spath/save=tour, 23 | line width=1pt, 24 | ] 25 | (1,1) 26 | -- ++(4,2) 27 | -- ++(-4,2) 28 | -- ++(2,-4) 29 | -- ++(2,4) 30 | -- ++(-4,-2) 31 | -- ++(4,-2) 32 | -- ++(-2,4) 33 | -- ++(-2,-4) 34 | ; 35 | 36 | \tikzset{ 37 | spath/.cd, 38 | split at self intersections=tour, 39 | remove empty components=tour, 40 | insert gaps after components={tour}{5pt}{1,3,...,31}, 41 | spot weld, 42 | get components of={tour}\pathcomponents, 43 | } 44 | 45 | \foreach[count=\k] \cpt in \pathcomponents { 46 | \draw[line width=1pt,spath/restore=\cpt]; 47 | % \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 48 | } 49 | 50 | \end{tikzpicture} 51 | 52 | \begin{tikzpicture}[ 53 | x={(30pt,0pt)}, 54 | y={(0pt,30pt)} 55 | ] 56 | 57 | \foreach \x in {0,1,...,7} 58 | { 59 | \foreach[evaluate=\y as \xy using {int(mod(\x+\y,2))}] \y in {0,1,...,7} 60 | { 61 | \ifnum\xy=0\relax 62 | \fill[gray!50!white] (\x-4,\y-4) rectangle +(1,1); 63 | \fi 64 | } 65 | } 66 | \draw (-4,-4) grid[step=1] +(8,8); 67 | 68 | \path[ 69 | % draw, 70 | gray!50!white, 71 | line width=3pt 72 | ] 73 | (-4,-4) 74 | ++(.5,.5) 75 | -- ++(2,1) 76 | -- ++(-2,1) 77 | -- ++(1,-2) 78 | -- ++(2,1) 79 | -- ++(1,2) 80 | -- ++(-2,1) 81 | -- ++(2,1) 82 | -- ++(-1,-2) 83 | -- ++(-2,1) 84 | -- ++(-1,2) 85 | -- ++(2,1) 86 | -- ++(-1,-2) 87 | -- ++(-1,2) 88 | -- ++(2,-1) 89 | -- ++(-2,-1) 90 | -- ++(1,2) 91 | -- ++(2,-1) 92 | -- ++(2,-1) 93 | -- ++(2,-1) 94 | -- ++(-1,2) 95 | -- ++(-2,1) 96 | -- ++(-1,-2) 97 | -- ++(2,-1) 98 | -- ++(2,-1) 99 | -- ++(-1,-2) 100 | -- ++(-2,-1) 101 | -- ++(1,2) 102 | -- ++(1,2) 103 | -- ++(1,2) 104 | -- ++(-2,1) 105 | -- ++(1,-2) 106 | -- ++(1,2) 107 | -- ++(-2,-1) 108 | -- ++(2,-1) 109 | -- ++(-1,2) 110 | -- ++(-2,-1) 111 | -- ++(-1,-2) 112 | -- ++(2,-1) 113 | -- ++(-2,-1) 114 | -- ++(1,2) 115 | -- ++(2,-1) 116 | -- ++(1,-2) 117 | -- ++(-2,-1) 118 | -- ++(1,2) 119 | -- ++(1,-2) 120 | -- ++(-2,1) 121 | -- ++(2,1) 122 | -- ++(-1,-2) 123 | -- ++(-2,1) 124 | -- ++(-2,1) 125 | -- ++(-2,1) 126 | -- ++(1,-2) 127 | -- ++(2,-1) 128 | -- ++(1,2) 129 | -- ++(-2,1) 130 | -- ++(-2,1) 131 | -- ++(1,2) 132 | -- ++(2,1) 133 | -- ++(-1,-2) 134 | -- ++(-1,-2) 135 | -- ++(-1,-2) 136 | -- ++(2,-1) 137 | -- ++(-1,2) 138 | %-- ++(-1,-2) 139 | -- cycle 140 | ; 141 | 142 | \path[ 143 | spath/save=corner, 144 | % draw 145 | ] 146 | (-4,-4) 147 | ++(1.5,3.5) 148 | -- ++(-1,-2) 149 | -- ++(2,-1) 150 | -- ++(-1,2) 151 | -- ++(-1,-2) 152 | -- ++(2,1) 153 | -- ++(-2,1) 154 | -- ++(1,-2) 155 | -- ++(2,1) 156 | %-- ++(1,2) 157 | ; 158 | 159 | \path[ 160 | spath/save=centre, 161 | % draw 162 | ] 163 | (-4,-4) 164 | ++(4.5,1.5) 165 | -- ++(-2,1) 166 | -- ++(-2,1) 167 | -- ++(1,-2) 168 | -- ++(2,-1) 169 | -- ++(1,2) 170 | %-- ++(-2,1) 171 | %-- ++(-2,1) 172 | ; 173 | 174 | \path[ 175 | spath/save=triangle, 176 | % draw, 177 | rotate=180 178 | ] 179 | (-4,-4) 180 | ++(3.5,1.5) 181 | -- ++(1,2) 182 | -- ++(-2,1) 183 | -- ++(2,1) 184 | -- ++(-1,-2) 185 | ; 186 | 187 | \path[ 188 | spath/save=centre line 189 | ] 190 | (.5,-1.5) 191 | -- ++(-2,1) 192 | ; 193 | 194 | \path[ 195 | spath/save=edge line 196 | ] 197 | (-.5,-2.5) 198 | -- ++(1,2) 199 | ; 200 | 201 | \tikzset{ 202 | % remove empty components=corner, 203 | % remove empty components=centre, 204 | % remove empty components=triangle, 205 | % 206 | spath/.cd, 207 | transform={corner}{scale=.5}, 208 | transform={centre}{scale=.5}, 209 | transform={triangle}{scale=.5}, 210 | transform={centre line}{scale=.5}, 211 | % 212 | clone={centre line 180}{centre line}, 213 | transform={centre line 180}{rotate=180}, 214 | % 215 | split at self intersections=corner, 216 | split at self intersections=centre, 217 | split at self intersections=triangle, 218 | % 219 | split at intersections={triangle}{centre line 180}, 220 | split at intersections={triangle}{centre line}, 221 | % 222 | clone={triangle 180}{triangle}, 223 | transform={triangle 180}{rotate=180}, 224 | % 225 | split at intersections={corner}{centre}, 226 | split at intersections={centre}{triangle 180}, 227 | split at intersections={triangle}{triangle 180}, 228 | % 229 | transform={corner}{scale=2}, 230 | transform={centre}{scale=2}, 231 | transform={triangle}{scale=2}, 232 | transform={triangle 180}{scale=2}, 233 | transform={centre line}{scale=2}, 234 | transform={centre line 180}{scale=2}, 235 | % 236 | insert gaps after components={corner}{5pt}{1,3,...,33}, 237 | insert gaps after components={centre}{5pt}{2,4,...,10}, 238 | insert gaps after components={triangle}{5pt}{1,3,...,11}, 239 | insert gaps after components={triangle 180}{5pt}{2,4,...,10}, 240 | insert gaps after components={centre line}{5pt}{1}, 241 | % 242 | clone={tour}{corner}, 243 | clone={centre reversed}{centre}, 244 | % 245 | transform={edge line}{rotate=-90}, 246 | transform={corner}{rotate=-90}, 247 | transform={centre}{rotate=180}, 248 | transform={centre line}{rotate=180}, 249 | transform={centre reversed}{rotate=90}, 250 | % 251 | reverse=centre reversed, 252 | reverse=corner, 253 | reverse=edge line, 254 | % 255 | join with={tour}{triangle 180}, 256 | join with={tour}{edge line}, 257 | join with={tour}{corner}, 258 | join with={tour}{centre}, 259 | join with={tour}{centre line}, 260 | join with={tour}{centre reversed}, 261 | % 262 | clone={tour 180}{tour}, 263 | transform={tour 180}{rotate=180}, 264 | % 265 | join with={tour}{tour 180}, 266 | spot weld={tour}, 267 | export to svg={tour} 268 | % show spath={tour}, 269 | } 270 | 271 | \draw[line width=1pt, spath/restore=tour]; 272 | \end{tikzpicture} 273 | \end{document} 274 | -------------------------------------------------------------------------------- /examples/knot-examples.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | \documentclass{article} 4 | \usepackage{tikz} 5 | \usetikzlibrary{ 6 | knots, 7 | hobby, 8 | celtic, 9 | decorations.pathreplacing, 10 | shapes.geometric, 11 | calc 12 | } 13 | \usepackage{braids} 14 | 15 | \tikzset{ 16 | knot diagram/every strand/.append style={ 17 | ultra thick,red 18 | }, 19 | show curve controls/.style={ 20 | postaction=decorate, 21 | decoration={show path construction, 22 | curveto code={ 23 | \draw [blue, dashed] 24 | (\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta) 25 | node [at end, draw, solid, red, inner sep=2pt]{}; 26 | \draw [blue, dashed] 27 | (\tikzinputsegmentsupportb) -- (\tikzinputsegmentlast) 28 | node [at start, draw, solid, red, inner sep=2pt]{} 29 | node [at end, fill, blue, ellipse, inner sep=2pt]{} 30 | ; 31 | } 32 | } 33 | }, 34 | show curve endpoints/.style={ 35 | postaction=decorate, 36 | decoration={show path construction, 37 | curveto code={ 38 | \node [fill, blue, ellipse, inner sep=2pt] at (\tikzinputsegmentlast) {} 39 | ; 40 | } 41 | } 42 | } 43 | } 44 | 45 | \begin{document} 46 | 47 | \begin{tikzpicture} 48 | \begin{knot}[ 49 | consider self intersections=true, 50 | % draft mode=crossings, 51 | flip crossing={2}, 52 | only when rendering/.style={ 53 | spath/show current path, 54 | } 55 | ] 56 | \strand (0,2) .. controls +(2.2,0) and +(120:-2.2) .. (210:2) .. controls +(120:2.2) and +(60:2.2) .. (-30:2) .. controls +(60:-2.2) and +(-2.2,0) .. (0,2); 57 | \end{knot} 58 | \end{tikzpicture} 59 | 60 | \begin{tikzpicture} 61 | \begin{knot}[ 62 | consider self intersections=true, 63 | % draft mode=crossings, 64 | flip crossing/.list={2,4}, 65 | only when rendering/.style={ 66 | % show curve controls 67 | } 68 | ] 69 | \strand (2,0) .. controls +(0,1.0) and +(54:1.0) .. (144:2) .. controls +(54:-1.0) and +(18:-1.0) .. (-72:2) .. controls +(18:1.0) and +(162:-1.0) .. (72:2) .. controls +(162:1.0) and +(126:1.0) .. (-144:2) .. controls +(126:-1.0) and +(0,-1.0) .. (2,0); 70 | \end{knot} 71 | \end{tikzpicture} 72 | 73 | \begin{tikzpicture} 74 | \begin{knot}[ 75 | % draft mode=crossings, 76 | flip crossing=2 77 | ] 78 | \strand (1,0) circle[radius=2cm]; 79 | \strand[blue] (-1,0) circle[radius=2cm]; 80 | \end{knot} 81 | \end{tikzpicture} 82 | 83 | \begin{tikzpicture} 84 | \begin{knot}[ 85 | % draft mode=crossings, 86 | flip crossing/.list={3,4} 87 | ] 88 | \strand (1,0) circle[radius=2cm]; 89 | \strand[blue] (-1,0) circle[radius=2cm]; 90 | \strand[green] (0,{sqrt(3)}) circle[radius=2cm]; 91 | \end{knot} 92 | \end{tikzpicture} 93 | 94 | 95 | \begin{tikzpicture}[use Hobby shortcut] 96 | \begin{knot}[ 97 | consider self intersections=true, 98 | draft mode=crossings, 99 | ignore endpoint intersections=false, 100 | % flip crossing=3 101 | ] 102 | \strand ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1) .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 103 | \end{knot} 104 | \path (0,-.7); 105 | \end{tikzpicture} 106 | 107 | \end{document} 108 | -------------------------------------------------------------------------------- /examples/knot_pins.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | %\url{https://tex.stackexchange.com/q/440528/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{knots} 5 | 6 | \begin{document} 7 | 8 | \begin{tikzpicture} 9 | \node[draw,pin={[node contents={pin}]}] (a) {test}; 10 | \end{tikzpicture} 11 | 12 | \begin{tikzpicture} 13 | \begin{knot}[ 14 | draft mode=crossings, 15 | clip width=10pt, 16 | consider self intersections, 17 | end tolerance=1pt, 18 | draft/crossing 3 label/.style={ 19 | text=red, 20 | pin position=45, 21 | }, 22 | draft/crossing 1 label/.style={ 23 | text=green, 24 | pin position=135, 25 | } 26 | ] 27 | \strand[ultra thick] 28 | (0,0.3) to[out=180,in=90] 29 | (-1.2,-1.5) to[out=-90,in=180] 30 | (1,-3.5) to[out=0,in=0,looseness=2] 31 | (0,-1) to[out=180,in=180,looseness=2] 32 | (-1,-3.5) to[out=0,in=-90] 33 | (1.2,-1.5) to[out=90,in=0] (0,0.3); 34 | \end{knot} 35 | \end{tikzpicture} 36 | 37 | \end{document} 38 | -------------------------------------------------------------------------------- /examples/knot_shading.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | %\url{https://tex.stackexchange.com/q/410096/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{hobby,knots} 5 | 6 | \pgfdeclarelayer{back} 7 | \pgfsetlayers{back,main} 8 | 9 | \begin{document} 10 | 11 | \begin{tikzpicture}[use Hobby shortcut] 12 | 13 | \begin{scope}[blend group=darken] 14 | 15 | \begin{scope}[blend group=normal,even odd rule] 16 | \clip (0,0) circle[radius=1.07]; 17 | \fill[black!30!white, save Hobby path={knot}] ([closed]90:2) foreach \k in {1,...,7} 18 | { .. (90-360/7+\k*1080/7:1) .. (90+\k*1080/7:2) } (90:2); 19 | \end{scope} 20 | 21 | \begin{scope}[blend group=normal] 22 | \begin{knot}[ 23 | consider self intersections=true, 24 | ignore endpoint intersections = false, 25 | flip crossing/.list={1,7,6,11,10, 13, 15, 2} 26 | ] 27 | \strand[very thick] ([closed]90:2) foreach \k in {1,...,7} { .. (90-360/7+\k*1080/7:1) .. (90+\k*1080/7:2) } (90:2); 28 | \end{knot} 29 | \end{scope} 30 | 31 | \end{scope} 32 | \end{tikzpicture} 33 | \end{document} 34 | -------------------------------------------------------------------------------- /examples/knots_celtic.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{tikz} 3 | \usetikzlibrary{knots} 4 | 5 | \tikzset{ 6 | basic strand/.style={ 7 | red, 8 | line width=2pt, 9 | double=white, 10 | double distance=9pt, 11 | }, 12 | crossing strand/.style={ 13 | line width=13pt, 14 | only when rendering/.style={% 15 | draw=white,% 16 | line width=9pt, 17 | double=none, 18 | } 19 | } 20 | } 21 | 22 | \begin{document} 23 | 24 | \begin{tikzpicture}[scale=0.8] 25 | 26 | \begin{knot}[ 27 | % draft mode=crossings, 28 | consider self intersections=no splits, 29 | end tolerance=1pt,% 30 | line width=2pt ,% 31 | line join=round,% 32 | clip width=1,% 33 | ignore endpoint intersections=true,% 34 | background color=red,% 35 | every intersection/.style={ 36 | crossing strand 37 | }, 38 | only when rendering/.style={ 39 | basic strand 40 | }, 41 | flip crossing/.list={2,3,6,8} 42 | ] 43 | 44 | \strand (0.5,1) to [out=north, in=south] (2.5,4) to [out=north, in=south] 45 | (0.5,7) -- (0.5,7) -- (0.5,7.5) -- (1,7.5) to [out=east, in=west] (3,6.5) 46 | to [out=east, in=225] (4.5,7.5) to [out=45, in=south] (5.5,9) to 47 | [out=north, in=-45] (4.5,10.5) to [out=135,in=east] (3,11.5) to [out=west, 48 | in=45] (1.5,10.5) to [out=225,in=north] (0.5,9) -- (0.5,8.5) -- (1,8.5) to 49 | [out=east, in=south] (2.5,10) to [out=north, in=east](1,11.5) -- 50 | (0.5,11.5) -- (0.5,11) to [out=south, in=north] (2.5,8) to [out=south, 51 | in=north] (0.5,5) -- (0.5,4.5) -- (1,4.5) to [out=east, in=west] (3,5.5) 52 | to [out=east, in=135] (4.5,4.5) to [out=-45, in=north] (5.5,3) to 53 | [out=south, in=45] (4.5,1.5) to [out=225, in=east] (3,0.5) to [out=west, 54 | in=-45] (1.5,1.5) to [out=135, in=south] (0.5,3) -- (0.5,3.5) -- (1,3.5) 55 | to [out=east, in=north] (2.5,2) to [out=south, in=east] (1,0.5) -- 56 | (0.5,0.5) -- (0.5,1); 57 | \end{knot} 58 | 59 | \end{tikzpicture} 60 | \end{document} 61 | -------------------------------------------------------------------------------- /examples/knots_more_celtic.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{tikz} 3 | \usetikzlibrary{knots} 4 | 5 | \tikzset{ 6 | basic strand/.style={ 7 | draw=red, 8 | double=white, 9 | double distance=9pt, 10 | }, 11 | crossing strand/.style={ 12 | line width=13pt, 13 | only when rendering/.style={% 14 | draw=white,% 15 | line width=9pt, 16 | double=none, 17 | } 18 | } 19 | } 20 | 21 | \begin{document} 22 | 23 | \def\x{-569} % xshift 24 | \def\y{-341} %yshift 25 | 26 | \begin{tikzpicture}[scale=0.8] 27 | 28 | \draw[color=black!20!white] (0,0) grid[step=1] (20,12); 29 | \draw[line width=3] (0,0) -- (20,0) -- (20,12) -- (0,12) -- (0,0)% Rahmen 30 | (0,4)--(2,4)% Horizontal 31 | (0,8)--(2,8)% 32 | (2,6)--(4,6)% 33 | (5,7)--(7,7)% 34 | (5,5)--(7,5)% 35 | (8,6)--(12,6)% 36 | (9,9)--(11,9)% 37 | (9,3)--(11,3)% 38 | (13,7)--(15,7)% 39 | (13,5)--(15,5)% 40 | (16,6)--(18,6)% 41 | (18,8)--(20,8)% 42 | (18,4)--(20,4)% 43 | (3,1)--(3,5)% Vertikal 44 | (3,7)--(3,11)% 45 | (6,2)--(6,4)% 46 | (6,8)--(6,10)% 47 | (10,0)--(10,2)% 48 | (10,4)--(10,8)% 49 | (10,10)--(10,12)% 50 | (14,2)--(14,4)% 51 | (14,8)--(14,10)% 52 | (17,1)--(17,5)% 53 | (17,7)--(17,11)% 54 | ; 55 | 56 | \begin{knot}[consider self intersections=no splits, 57 | end tolerance=1pt,% 58 | line width=2pt ,% 59 | line join=round,% 60 | clip width=1,% 61 | ignore endpoint intersections=true,% 62 | background color=red,% 63 | every intersection/.style={ 64 | crossing strand 65 | }, 66 | only when rendering/.style={ 67 | basic strand 68 | }, 69 | ] 70 | 71 | \strand (0.5,1) to [out=north, in=south] (2.5,4) to [out=north, in=south] (0.5,7) -- (0.5,7) -- (0.5,7.5) -- (1,7.5) to [out=east, in=west] (3,6.5) to [out=east, in=225] (4.5,7.5) to [out=45, in=south] (5.5,9) to [out=north, in=-45] (4.5,10.5) to [out=135,in=east] (3,11.5) to [out=west, in=45] (1.5,10.5) to [out=225,in=north] (0.5,9) -- (0.5,8.5) -- (1,8.5) to [out=east, in=south] (2.5,10) to [out=north, in=east](1,11.5) -- (0.5,11.5) -- (0.5,11) to [out=south, in=north] (2.5,8) to [out=south, in=north] (0.5,5) -- (0.5,4.5) -- (1,4.5) to [out=east, in=west] (3,5.5) to [out=east, in=135] (4.5,4.5) to [out=-45, in=north] (5.5,3) to [out=south, in=45] (4.5,1.5) to [out=225, in=east] (3,0.5) to [out=west, in=-45] (1.5,1.5) to [out=135, in=south] (0.5,3) -- (0.5,3.5) -- (1,3.5) to [out=east, in=north] (2.5,2) to [out=south, in=east] (1,0.5) -- (0.5,0.5) -- (0.5,1); 72 | 73 | \strand[xscale=-1, xshift=\x] (0.5,1) to [out=north, in=south] (2.5,4) to [out=north, in=south] (0.5,7) -- (0.5,7) -- (0.5,7.5) -- (1,7.5) to [out=east, in=west] (3,6.5) to [out=east, in=225] (4.5,7.5) to [out=45, in=south] (5.5,9) to [out=north, in=-45] (4.5,10.5) to [out=135,in=east] (3,11.5) to [out=west, in=45] (1.5,10.5) to [out=225,in=north] (0.5,9) -- (0.5,8.5) -- (1,8.5) to [out=east, in=south] (2.5,10) to [out=north, in=east](1,11.5) -- (0.5,11.5) -- (0.5,11) to [out=south, in=north] (2.5,8) to [out=south, in=north] (0.5,5) -- (0.5,4.5) -- (1,4.5) to [out=east, in=west] (3,5.5) to [out=east, in=135] (4.5,4.5) to [out=-45, in=north] (5.5,3) to [out=south, in=45] (4.5,1.5) to [out=225, in=east] (3,0.5) to [out=west, in=-45] (1.5,1.5) to [out=135, in=south] (0.5,3) -- (0.5,3.5) -- (1,3.5) to [out=east, in=north] (2.5,2) to [out=south, in=east] (1,0.5) -- (0.5,0.5) -- (0.5,1); 74 | 75 | \strand (10,8.5) to [out=west, in=45] (8.5,7.5) to (7.5,6.5) to [out=225, in=east] (6,5.5) to [out=west, in=-45] (4.5,6.5) to [out=135, in=south] (3.5,8) to [out=north, in=225] (4.5,9.5) to (5.5,10.5) to [out=45, in=west] (7,11.5) to [out=east, in=135] (8.5,10.5) to [out=-45, in=west] (10,9.5) to [out=east, in=225] (11.5,10.5) to[out=45, in=west] (13,11.5) to [out=east, in=135] (14.5,10.5) to (15.5,9.5) to [out=-45, in=north] (16.5,8) to [out=south, in=45] (15.5,6.5) to [out=225, in=east] (14,5.5) to [out=west, in=-45] (12.5,6.5) to (11.5,7.5) to [out=135, in=east] (10,8.5); 76 | 77 | \strand[yscale=-1, yshift=\y] (10,8.5) to [out=west, in=45] (8.5,7.5) to (7.5,6.5) to [out=225, in=east] (6,5.5) to [out=west, in=-45] (4.5,6.5) to [out=135, in=south] (3.5,8) to [out=north, in=225] (4.5,9.5) to (5.5,10.5) to [out=45, in=west] (7,11.5) to [out=east, in=135] (8.5,10.5) to [out=-45, in=west] (10,9.5) to [out=east, in=225] (11.5,10.5) to[out=45, in=west] (13,11.5) to [out=east, in=135] (14.5,10.5) to (15.5,9.5) to [out=-45, in=north] (16.5,8) to [out=south, in=45] (15.5,6.5) to [out=225, in=east] (14,5.5) to [out=west, in=-45] (12.5,6.5) to (11.5,7.5) to [out=135, in=east] (10,8.5); 78 | 79 | \strand (3.5,10) to [out=north, in=west] (5,11.5) to [out=east, in=135] (6.5,10.5) to (8.5,8.5) to [out=-45, in=north] (9.5,7) -- (9.5,6.5) -- (9,6.5) to [out=west, in=-45] (7.5,7.5) to [out=135, in=south] (6.5,9) to [out=north, in=225] (7.5,10.5) to [out=45, in=west] (9,11.5) -- (9.5,11.5) -- (9.5,11) to [out=south, in=45] (8.5,9.5) to (7.5,8.5) to [out=225, in=east] (6,7.5) to [out=west, in=-45] (4.5,8.5) to [out=135, in=south] (3.5,10); 80 | 81 | \strand[xscale=-1, xshift=\x] (3.5,10) to [out=north, in=west] (5,11.5) to [out=east, in=135] (6.5,10.5) to (8.5,8.5) to [out=-45, in=north] (9.5,7) -- (9.5,6.5) -- (9,6.5) to [out=west, in=-45] (7.5,7.5) to [out=135, in=south] (6.5,9) to [out=north, in=225] (7.5,10.5) to [out=45, in=west] (9,11.5) -- (9.5,11.5) -- (9.5,11) to [out=south, in=45] (8.5,9.5) to (7.5,8.5) to [out=225, in=east] (6,7.5) to [out=west, in=-45] (4.5,8.5) to [out=135, in=south] (3.5,10); 82 | 83 | \strand[yscale=-1, yshift=\y] (3.5,10) to [out=north, in=west] (5,11.5) to [out=east, in=135] (6.5,10.5) to (8.5,8.5) to [out=-45, in=north] (9.5,7) -- (9.5,6.5) -- (9,6.5) to [out=west, in=-45] (7.5,7.5) to [out=135, in=south] (6.5,9) to [out=north, in=225] (7.5,10.5) to [out=45, in=west] (9,11.5) -- (9.5,11.5) -- (9.5,11) to [out=south, in=45] (8.5,9.5) to (7.5,8.5) to [out=225, in=east] (6,7.5) to [out=west, in=-45] (4.5,8.5) to [out=135, in=south] (3.5,10); 84 | 85 | \strand[xscale=-1, xshift=\x, yscale=-1, yshift=\y] (3.5,10) to [out=north, in=west] (5,11.5) to [out=east, in=135] (6.5,10.5) to (8.5,8.5) to [out=-45, in=north] (9.5,7) -- (9.5,6.5) -- (9,6.5) to [out=west, in=-45] (7.5,7.5) to [out=135, in=south] (6.5,9) to [out=north, in=225] (7.5,10.5) to [out=45, in=west] (9,11.5) -- (9.5,11.5) -- (9.5,11) to [out=south, in=45] (8.5,9.5) to (7.5,8.5) to [out=225, in=east] (6,7.5) to [out=west, in=-45] (4.5,8.5) to [out=135, in=south] (3.5,10); 86 | 87 | \flipcrossings{2,3,6,8,10,12,14,16,18,21,22,24,26,28,30,32,34,36,38,39,40,42,44,48,50,51,55,57,59,60,61,63,65,67,70,72,74} 88 | 89 | \end{knot} 90 | \end{tikzpicture} 91 | \end{document} -------------------------------------------------------------------------------- /examples/knots_small.tex: -------------------------------------------------------------------------------- 1 | \documentclass{memoir} 2 | %\url{https://tex.stackexchange.com/q/554924/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{knots} 5 | 6 | \begin{document} 7 | 8 | \def\rings{ 9 | \begin{tikzpicture} 10 | \begin{knot}[ 11 | clip radius=1.8pt, 12 | clip draw radius=1.9pt, 13 | end tolerance=2pt, 14 | clip width=3, 15 | flip crossing/.list={1,3}, 16 | ] 17 | \strand [line width=0.7pt, black] (0,0) ellipse (3.2pt and 2.2pt);%circle (1.0cm); 18 | \strand [line width=0.7pt, black] (4pt,0) ellipse (3.2pt and 2.2pt);%circle (1.0cm); 19 | \strand [line width=0.7pt, black] (8pt,0) ellipse (3.2pt and 2.2pt);%circle (1.0cm); 20 | \end{knot} 21 | \end{tikzpicture} 22 | } 23 | 24 | \fancybreak{\rings} 25 | 26 | \def\ringsA{ 27 | \begin{tikzpicture}[scale=0.1] 28 | \begin{knot}[ 29 | clip radius=1.8pt, 30 | clip draw radius=1.9pt, 31 | end tolerance=2pt, 32 | flip crossing/.list={1,3}, 33 | ] 34 | \strand [line width=0.7pt, black] (0,0) ellipse (1.2 and 0.8);%circle (1.0cm); 35 | \strand [line width=0.7pt, black] (1.5,0) ellipse (1.2 and 0.8);%circle (1.0cm); 36 | \strand [line width=0.7pt, black] (3,0) ellipse (1.2 and 0.8);%circle (1.0cm); 37 | \end{knot} 38 | \end{tikzpicture} 39 | } 40 | 41 | \fancybreak{\ringsA} 42 | 43 | \fancybreak{***} 44 | 45 | \end{document} 46 | -------------------------------------------------------------------------------- /examples/knots_test.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | %\immediate\write18{tex knots.dtx} 4 | \documentclass{article} 5 | \RequirePackage[enable-debug]{expl3} 6 | \ExplSyntaxOn 7 | \debug_on:n {check-declarations, deprecation} 8 | \ExplSyntaxOff 9 | \usepackage{tikz} 10 | \usetikzlibrary{knots,intersections,decorations.pathreplacing,hobby} 11 | 12 | \tikzset{ 13 | path details/.style={ 14 | >=stealth, 15 | every node/.style={ 16 | midway, 17 | sloped, 18 | font=\tiny 19 | }, 20 | } 21 | } 22 | 23 | \begin{document} 24 | 25 | \begin{tikzpicture} 26 | \begin{knot}[ 27 | % draft mode=crossings, 28 | flip crossing=2, 29 | name=knot, 30 | background colour=yellow, 31 | % save intersections, 32 | ] 33 | \strand[red] (0,0) .. controls +(1,0) and +(-1,0) .. (3,2) .. controls +(1,0) and +(-1,0) .. (6,0); 34 | \strand[blue] (0,2) .. controls +(1,0) and +(-1,0) .. (3,0) .. controls +(1,0) and +(-1,0) .. (6,2); 35 | \redraw{1}{([xshift=-1.5cm,yshift=1cm]knot 2)} 36 | \end{knot} 37 | \end{tikzpicture} 38 | 39 | 40 | \begin{tikzpicture}[ 41 | use Hobby shortcut, 42 | every path/.style={ 43 | line width=1mm, 44 | white, 45 | double=red, 46 | double distance=.5mm 47 | } 48 | ] 49 | \def\nfoil{10} 50 | \draw ([closed]0,2) 51 | \foreach \k in {1,...,\nfoil} { 52 | .. ([blank=soft]90+360*\k/\nfoil-180/\nfoil:-.5) .. (90+360*\k/\nfoil:2) 53 | }; 54 | \draw[use previous Hobby path={invert soft blanks,disjoint}]; 55 | \end{tikzpicture} 56 | 57 | \begin{tikzpicture} 58 | \begin{knot}[ 59 | consider self intersections=true, 60 | draft mode=crossings, 61 | clip radius=8pt, 62 | every strand/.style={line width=4pt,draw=red} 63 | ] 64 | \strand[rounded corners=4pt,only when rendering/.style={sharp corners}] 65 | (0,2.5) -- (1.5,2.5) -- (1.5,0.5) -- (0.5,0.5)-- (0.5,1.5) -- (3,1.5); 66 | \end{knot} 67 | \end{tikzpicture} 68 | 69 | \begin{tikzpicture} 70 | \draw (1.5,.5) -- (1.5,-.5) (2.5,.5) -- (2.5,-.5); 71 | \draw (0,.2) -- (4,.2); 72 | \draw[knot=red,knot gap=4,thick] (0,0) -- (2,0); 73 | \draw[thick] (2,0) -- (4,0); 74 | \end{tikzpicture} 75 | 76 | 77 | \begin{tikzpicture} 78 | \begin{knot} 79 | \strand (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 80 | \end{knot} 81 | \end{tikzpicture} 82 | 83 | \begin{tikzpicture} 84 | \begin{knot}[ 85 | consider self intersections, 86 | draft mode=crossings, 87 | ] 88 | \strand (0,0) .. controls +(.5,1) and +(1,0) .. (0,0.5); 89 | \end{knot} 90 | \end{tikzpicture} 91 | 92 | \begin{tikzpicture} 93 | \begin{knot}[ 94 | consider self intersections, 95 | draft mode=crossings, 96 | ] 97 | \strand (0,0) .. controls +(3,1) and +(-3,1) .. (1,0); 98 | \end{knot} 99 | \end{tikzpicture} 100 | 101 | 102 | \begin{tikzpicture} 103 | \begin{knot}[ 104 | consider self intersections=no splits, 105 | draft mode=crossings, 106 | ] 107 | \strand (0,0) .. controls +(1.5,.5) and +(1,0) .. (.5,1) .. controls +(-1,0) and +(-1.5,.5) .. (1,0); 108 | \end{knot} 109 | \end{tikzpicture} 110 | 111 | 112 | \newcommand{\motif}[1]{ 113 | to ++(180+#1:0.50) arc (270+#1:150+#1:0.15) 114 | to ++( 60+#1:0.50) arc (-30+#1:150+#1:0.15) 115 | to ++(240+#1:0.25) arc (150+#1:330+#1:0.25) 116 | to ++( 60+#1:0.55) arc (150+#1: 30+#1:0.20) 117 | } 118 | \newcommand{\celticknot}{\motif{0}\motif{120}\motif{240}} 119 | \begin{tikzpicture} 120 | \begin{knot}[ 121 | line width=2pt, 122 | line join=round, 123 | clip width=2, 124 | clip radius=16pt, 125 | end tolerance=20pt, 126 | scale=8, 127 | consider self intersections, 128 | ignore endpoint intersections=false, 129 | background color=white, 130 | intersection 12/.style={/tikz/knot diagram/clip radius=13pt}, 131 | every strand/.style={draw=none}, 132 | /tikz/only when rendering/.style={ 133 | draw=red, 134 | double=white, 135 | double distance=6pt, 136 | line cap=round, 137 | } 138 | % draft mode=crossings, 139 | ] 140 | \strand (0,0) \celticknot; 141 | \flipcrossings{1,3,6,8,10} 142 | \end{knot} 143 | \end{tikzpicture} 144 | 145 | \begin{tikzpicture} 146 | \node (A) at (0,4) [draw,minimum width=30pt,minimum height=10pt,thick] {}; 147 | \begin{knot}[ 148 | % draft mode=crossings, 149 | background colour=white, 150 | clip width=5, 151 | clip radius=8pt, 152 | % consider self intersections, 153 | ] 154 | \strand [thick,only when rendering/.style={dashed}] (0,0) 155 | to [out=up, in=down] (-1,1) 156 | to [out=up, in=down] (0,2) 157 | to [out=up, in=down] (-1.2,4) 158 | to [out=up, in=down, looseness=0.7] (0,5.5) 159 | to [out=up, in=down] (-2,7); 160 | \strand [thick] (-1,0) 161 | to [out=up, in=down] (1,2) 162 | to [out=up, in=down] (A.south); 163 | \strand [thick,only when rendering/.style={blue}] (1,0) 164 | to [out=up, in=down] (-1,2) 165 | to [out=up, in=down] (1.5,4) 166 | to [out=up, in=right] (0,5.5)to [out=left, in=up] (-2,4) 167 | to [out=down, in=up] (-2,0); 168 | \strand [thick] (A.150) 169 | to [out=up, in=down] (0.7,5.5) 170 | to [out=up, in=down] (0,7); 171 | \strand [thick] (A.30) 172 | to [out=up, in=down] (-1,6) 173 | to [out=up, in=down] (2,7); 174 | \flipcrossings{6,2,9,5,11} 175 | %\redraw{3}{(0,5.5)} 176 | \end{knot} 177 | \end{tikzpicture} 178 | \end{document} 179 | %% \documentclass{article} 180 | %% \usepackage{tikz} 181 | %% \usepackage{knots} 182 | %% \begin{document} 183 | %% \tikzset{knot/only when rendering/.style={draw=white, double=red}} 184 | %% \newsavebox{\firstbox} 185 | %% \sbox{\firstbox}{\begin{tikzpicture}[remember picture] 186 | %% \begin{knot} 187 | %% \strand (1,0) to (0,1); 188 | %% \strand (0,0) to (1,1); 189 | %% \end{knot} 190 | %% \end{tikzpicture}} 191 | %% \newsavebox{\secondbox} 192 | %% \sbox{\secondbox}{\begin{tikzpicture}[remember picture] 193 | %% \node at (0,0) {hello}; 194 | %% \end{tikzpicture}} 195 | %% \begin{tikzpicture} 196 | %% \node at (0,0) {\usebox\firstbox}; 197 | %% \node at (1,0) {\usebox\secondbox}; 198 | %% \end{tikzpicture} 199 | %% \end{document} 200 | %\documentclass{article} 201 | %\usepackage{nopageno,tikz,knots,geometry} 202 | %\geometry{landscape} 203 | 204 | \definecolor{SafetyOrange}{rgb}{1,0.4,0} 205 | \definecolor{LuminousOrange}{rgb}{1,0.137255,0.00392157} 206 | 207 | %\begin{document} 208 | 209 | \hspace{-0.75in} 210 | \noindent 211 | \newcommand{\motif}[1]{ 212 | to ++(180+#1:0.50) arc (270+#1:150+#1:0.15) 213 | to ++( 60+#1:0.50) arc (-30+#1:150+#1:0.15) 214 | to ++(240+#1:0.25) arc (150+#1:330+#1:0.25) 215 | to ++( 60+#1:0.55) arc (150+#1: 30+#1:0.20) 216 | } 217 | \newcommand{\celticknot}{\motif{0}\motif{120}\motif{240}} 218 | \begin{tikzpicture} 219 | \begin{knot}[ 220 | line width=6pt, 221 | line join=round, 222 | clip width=1.5, 223 | clip radius=16pt, 224 | end tolerance=20pt, 225 | scale=8, 226 | consider self intersections, 227 | ignore endpoint intersections=false, 228 | background color=red, 229 | intersection 12/.style={/tikz/knot diagram/clip radius=13pt}, 230 | every strand/.style={draw=none}, 231 | only when rendering/.style={draw=red,double=white,line cap=round,double distance=6pt}, 232 | ] 233 | \strand (0,0) \celticknot; 234 | \flipcrossings{1,3,6,8,10} 235 | \end{knot} 236 | \end{tikzpicture} 237 | 238 | \vfill 239 | 240 | %\end{document} 241 | 242 | %\documentclass{article} 243 | %\usepackage{tikz,knots} 244 | 245 | 246 | \newcommand{\motif}[1]{ to ++(180+#1:0.5) arc (270+#1:150+#1:0.15) to ++(60+#1:0.5) arc (-30+#1:150+#1:0.15) to ++(240+#1:0.25) arc (150+#1:330+#1:0.25) to ++(60+#1:0.5) arc (150+#1:30+#1:0.2) } 247 | \newcommand{\celticknot}{\motif{0}\motif{120}\motif{240}} 248 | \begin{document} 249 | \begin{tikzpicture}[line width=3,line join=round,scale=2] 250 | \path[draw=none] (0,0) -- (2,0); 251 | \begin{knot}[ 252 | clip width=1.5pt, 253 | clip radius=10pt, 254 | end tolerance=10pt, 255 | % background colour=red, 256 | scale=2, 257 | % draft mode=crossings, 258 | consider self intersections=no splits, 259 | ignore endpoint intersections=false, 260 | draft/crossing label/.style={text opacity=1,text=blue,anchor=south east,append after command={(\tikzlastnode.center) edge[blue,->,thin] (\tikzlastnode.south east)}}, 261 | ] 262 | \strand[draw=none,only when rendering/.style={draw,double}] (0,0) \celticknot; 263 | \flipcrossings{9,7,5,2,4,11,12} 264 | \end{knot} 265 | \end{tikzpicture} 266 | %\end{document} 267 | \begin{tikzpicture} 268 | \begin{knot}[ 269 | consider self intersections, 270 | ] 271 | \strand (0,0) .. controls +(2,1) and +(-2,1) .. (1,0); 272 | \end{knot} 273 | \end{tikzpicture} 274 | %\end{document} 275 | %\documentclass{article} 276 | %\usepackage{tikz} 277 | %\usepackage{knots} 278 | %\begin{document} 279 | \begin{tikzpicture} 280 | \braid[ 281 | rotate=90, 282 | ultra thick, 283 | style strands={1}{red}, 284 | style strands={2}{black}, 285 | style strands={3}{blue}, 286 | style strands={4}{green}, 287 | ] a_1 a_1 a_2^{-1} a_2^{-1} a_1^{-1} a_1^{-1} a_2 a_2 a_2 a_3^{-1} a_3^{-1} a_2^{-1} a_2^{-1} a_2^{-1} a_1 a_1 a_2 a_2 a_1^{-1} a_1^{-1} a_2 a_3 a_3 a_2^{-1}; 288 | \end{tikzpicture} 289 | \end{document} 290 | %% \usepackage{tikz} 291 | %% \usepackage{knots} 292 | %% \begin{document} 293 | %% \begin{tikzpicture} 294 | %% \draw (0,0) -- (1,0); 295 | %% \begin{scope}[line width=2pt,scale=2,rotate=45]%,shift={(1cm,2cm)}] 296 | %% \begin{knot}[draft mode=crossings] 297 | %% \strand[red] (0,0) -- (2,2); 298 | %% \strand[blue] (2,0) -- (0,2); 299 | %% \end{knot} 300 | %% \end{scope} 301 | %% \end{tikzpicture} 302 | %% \end{document} 303 | 304 | 305 | 306 | \begin{tikzpicture}[line width=6,line join=round,scale=1.5] 307 | %\def\x{1.5} 308 | %\def\y{1.5} 309 | \def\x{1} 310 | \def\y{1} 311 | \begin{knot}[clip width=1.5] 312 | \strand[red ] (0*\x,0.0*\y) to (14*\x,0*\y); 313 | \strand[blue ] (0*\x,1.0*\y) to (14*\x,1*\y); 314 | \strand[green] (0*\x,2.0*\y) to (14*\x,2*\y); 315 | \strand[black] (0*\x,0.5*\y) to[out=right,in=left] ++(\x,0) 316 | to ++(0,-1*\y) to[out=down,in=down] ++(\x,0) 317 | to ++(0, 2*\y) to[out=up ,in=up ] ++(\x,0) 318 | to ++(0,-2*\y) to[out=down,in=down] ++(\x,0) 319 | to ++(0, 2*\y) to[out=up ,in=up ] ++(\x,0) 320 | to ++(0,-1*\y) to[out=down,in=down] ++(\x,0) 321 | to ++(0, 2*\y) to[out=up ,in=up ] ++(\x,0) 322 | to ++(0,-2*\y) to[out=down,in=down] ++(\x,0) 323 | to ++(0, 1*\y) to[out=up ,in=up ] ++(\x,0) 324 | to ++(0,-2*\y) to[out=down,in=down] ++(\x,0) 325 | to ++(0, 2*\y) to[out=up ,in=up ] ++(\x,0) 326 | to ++(0,-2*\y) to[out=down,in=down] ++(\x,0) 327 | to ++(0, 3*\y) to[out=up ,in=up ] ++(\x,0) 328 | to ++(0,-2*\y) to[out=right,in=left] ++(\x,0) 329 | ; 330 | \flipcrossings{1,4,5,8,9,12,15,18,21,24} 331 | \end{knot} 332 | \draw 333 | ( 1.5*\x,-0.5*\y) node {\LARGE$a$} 334 | ( 2.5*\x, 1.5*\y) node {\LARGE$b$} 335 | ( 3.5*\x,-0.5*\y+0.1) node {\LARGE$a^{-1}$} 336 | ( 4.5*\x, 1.5*\y-0.1) node {\LARGE$b^{-1}$} 337 | ( 6.5*\x, 2.5*\y) node {\LARGE$c$} 338 | ( 8.5*\x, 1.5*\y) node {\LARGE$b$} 339 | ( 9.5*\x,-0.5*\y) node {\LARGE$a$} 340 | (10.5*\x, 1.5*\y-0.1) node {\LARGE$b^{-1}$} 341 | (11.5*\x,-0.5*\y+0.1) node {\LARGE$a^{-1}$} 342 | (12.5*\x, 2.5*\y-0.1) node {\LARGE$c^{-1}$} 343 | ; 344 | \end{tikzpicture} 345 | 346 | \vfill 347 | 348 | \end{document} 349 | %\documentclass[border=10]{standalone} 350 | \begin{tikzpicture} 351 | \begin{knot}[draft mode] 352 | \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); 353 | \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); 354 | \crossing{1-2-1}{1} 355 | \crossing{1-2-2}{2} 356 | \crossing{1-2-3}{1} 357 | \crossing{1-2-4}{2} 358 | \end{knot} 359 | \end{tikzpicture} 360 | 361 | \begin{tikzpicture} 362 | \begin{knot}[draft mode=false] 363 | \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); 364 | \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); 365 | \crossing{1-2-1}{1} 366 | \crossing{1-2-2}{2} 367 | \crossing{1-2-3}{1} 368 | \crossing{1-2-4}{2} 369 | \end{knot} 370 | \end{tikzpicture} 371 | \end{document} 372 | 373 | \begin{tikzpicture} 374 | \draw[ultra thick, red,save path=\toppath] (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); 375 | \draw[ultra thick, blue,save path=\botpath] (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); 376 | %\pgfintersectionsortbyfirstpath 377 | \pgfintersectionofpaths{\pgfsetpath\toppath}{\pgfsetpath\botpath} 378 | \foreach \intsect in {1,...,\pgfintersectionsolutions} { 379 | \pgfpointintersectionsolution{\intsect} 380 | \pgfgetlastxy{\intsectx}{\intsecty} 381 | \node[circle,fill=white] at (\intsectx,\intsecty) {\intsect}; 382 | } 383 | \begin{scope}[yshift=-3cm] 384 | \draw[ultra thick, red] (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); 385 | \draw[ultra thick, blue] (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); 386 | \foreach \intsect in {1,...,\pgfintersectionsolutions} { 387 | \begin{scope} 388 | \pgfpointintersectionsolution{\intsect} 389 | \pgfgetlastxy{\intsectx}{\intsecty} 390 | \clip (\intsectx,\intsecty) circle[radius=10pt]; 391 | \ifodd\intsect 392 | \draw[ultra thick,double=red,double distance=1.6pt,white] (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); 393 | \fi 394 | \draw[ultra thick,double=blue,double distance=1.6pt,white] (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); 395 | \ifodd\intsect 396 | \else 397 | \draw[ultra thick,double=red,double distance=1.6pt,white] (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); 398 | \fi 399 | \end{scope} 400 | } 401 | \end{scope} 402 | \end{tikzpicture} 403 | \end{document} 404 | 405 | \documentclass{article} 406 | \usepackage{tikz} 407 | \usetikzlibrary{intersections} 408 | \usepackage{spath} 409 | 410 | \makeatletter 411 | \def\splitcurveto#1#2\pgfsyssoftpath@curvetosupportatoken#3#4\pgfsyssoftpath@curvetosupportbtoken#5#6\pgfsyssoftpath@curvetotoken#7#8{% 412 | \pgfmathsetmacro{\knot@ax}{#1/28} 413 | \pgfmathsetmacro{\knot@bx}{#3/28} 414 | \pgfmathsetmacro{\knot@cx}{#5/28} 415 | \pgfmathsetmacro{\knot@dx}{#7/28} 416 | \pgfmathsetmacro{\knot@ay}{#2/28} 417 | \pgfmathsetmacro{\knot@by}{#4/28} 418 | \pgfmathsetmacro{\knot@cy}{#6/28} 419 | \pgfmathsetmacro{\knot@dy}{#8/28} 420 | \message{Got (\knot@ax,\knot@ay), (\knot@bx,\knot@by), (\knot@cx,\knot@cy), (\knot@cx,\knot@cy)} 421 | \pgfmathsetmacro{\splittimenum}{% 422 | ( (\knot@ay - 3 * \knot@by + 3 * \knot@cy - \knot@dy) * (3 * \knot@cx - 3 * \knot@dx) 423 | - (\knot@ax - 3 * \knot@bx + 3 * \knot@cx - \knot@dx) * (3 * \knot@cy - 3 * \knot@dy) )} 424 | \pgfmathsetmacro{\splittimeden}{% 425 | ( (\knot@ax - 3 * \knot@bx + 3 * \knot@cx - \knot@dx) * (3 * \knot@by - 6 * \knot@cy + 3 * \knot@dy) 426 | - (\knot@ay - 3 * \knot@by + 3 * \knot@cy - \knot@dy) * (3 * \knot@bx - 6 * \knot@cx + 3 * \knot@dx) )} 427 | \pgfmathsetmacro{\splittime}{.5*\splittimenum/\splittimeden} 428 | \pgfpointcurveattime{\splittime}{\pgfqpoint{#1}{#2}}{\pgfqpoint{#3}{#4}}{\pgfqpoint{#5}{#6}}{\pgfqpoint{#7}{#8}} 429 | \global\pgf@xa=\pgf@x 430 | \global\pgf@ya=\pgf@y 431 | } 432 | \def\splitit{\message{split it}} 433 | \def\nosplitit{\message{don't split it}} 434 | \makeatother 435 | 436 | \begin{document} 437 | \begin{tikzpicture} 438 | \makeatletter 439 | \draw[save path=\tmppath] (0,0) .. controls +(3,3) and +(2,-2) .. (0,1); 440 | \draw[save path=\tmppath] (0,0) .. controls (2,1) and (-1,1) .. (1,0); 441 | \begingroup 442 | \let\pgfsyssoftpath@movetotoken=\splitcurveto 443 | \tmppath 444 | \endgroup 445 | \fill (\the\pgf@xa,\the\pgf@ya) circle[radius=2pt]; 446 | \makeatother 447 | 448 | \end{tikzpicture} 449 | \end{document} 450 | \begin{tikzpicture} 451 | \makeatletter 452 | \foreach \k in {0,...,-10} { 453 | \begin{scope}[yshift=\k cm] 454 | \draw[save path=\tmppath] (0,0) .. controls +(3,3) and +(2,-2) .. (\k,1); 455 | \draw[red] (0,0) -- (3,3) -- (\k + 2,-1) -- (\k,1); 456 | \begingroup 457 | \let\pgfsyssoftpath@movetotoken=\splitcurveto 458 | \tmppath 459 | \endgroup 460 | \end{scope} 461 | \fill (\the\pgf@xa,\the\pgf@ya) circle[radius=2pt]; 462 | } 463 | \makeatother 464 | 465 | 466 | 467 | \end{tikzpicture} 468 | \end{document} 469 | \draw[save path=\tmppath] (0,0) -- (1,1) .. controls +(1,1) and +(1,-1) .. (1,0) -- (0,1); 470 | \pgfintersectionofpaths{\pgfsetpath\tmppath}{\pgfsetpath\tmppath} 471 | \foreach \ints in {1,...,\pgfintersectionsolutions} { 472 | \pgfpointintersectionsolution{\ints} 473 | \pgfgetlastxy{\intsectx}{\intsecty} 474 | \fill (\intsectx,\intsecty) circle[radius=2pt]; 475 | } 476 | \end{tikzpicture} 477 | \end{document} 478 | 479 | 480 | % Local Variables: 481 | % tex-output-type: "pdf18" 482 | % End: 483 | -------------------------------------------------------------------------------- /examples/knots_triple.tex: -------------------------------------------------------------------------------- 1 | \documentclass{amsart} 2 | %\url{https://tex.stackexchange.com/q/438822/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{positioning,knots} 5 | 6 | \begin{document} 7 | 8 | \[ 9 | \begin{tikzpicture} 10 | 11 | \node (KS1) at (0,0){}; 12 | \node (KS2) [below=1 of KS1]{}; 13 | \node (KS3) [below=1 of KS2]{}; 14 | \node (KC1) [right=1 of KS2] {}; 15 | \node (KC2) [right=1 of KC1] {}; 16 | \node (KT1) [above right=1 and 1 of KC2]{}; 17 | \node (KT2) [below=1 of KT1]{}; 18 | \node (KT3) [below=1 of KT2]{}; 19 | 20 | \begin{knot}[draft mode=crossings] 21 | \strand[->] (KS1) 22 | to [out=0, in=135] (KC1) 23 | to [out=-45,in=-135] (KC2) 24 | to [out=45, in=180] (KT1); 25 | \strand[->] (KS2) 26 | to [out=0, in=180] (KC1) 27 | to [out=0, in=180] (KC2) 28 | to [out=0, in=180] (KT2); 29 | \strand[->] (KS3) 30 | to [out=0, in=-135] (KC1) 31 | to [out=45, in=135] (KC2) 32 | to [out=-45, in=180] (KT3); 33 | \redraw{1}{(KC2)} 34 | \end{knot} 35 | 36 | \end{tikzpicture} 37 | \] 38 | 39 | \end{document} 40 | 41 | \documentclass{amsart} 42 | 43 | \usepackage{tikz} 44 | \usetikzlibrary{positioning,knots} 45 | 46 | \begin{document} 47 | 48 | \begin{tikzpicture}[scale=3] 49 | \begin{knot}[ 50 | draft mode=crossings 51 | ] 52 | \strand[->] (0,0) to[out=0,in=180] (1,-1.5) to[out=0,in=180] (2,0); 53 | \strand[->] (0,-1) -- ++(2,0);% to[out=0,in=180] (1,-1) to[out=0,in=180] (2,-1); 54 | \strand[->] (0,-2) to[out=0,in=180] (1,-.5) to[out=0,in=180] (2,-2); 55 | % 56 | % None: 3,1,2 57 | % 2: 3,1,2 58 | % 4: 1,3,2 59 | % 6: 1,2,3 60 | \end{knot} 61 | \end{tikzpicture} 62 | 63 | \vspace*{2cm} 64 | 65 | %\[ 66 | \begin{tikzpicture}[scale=3] 67 | 68 | \coordinate (KS1) at (0,0){}; 69 | \coordinate [below=1 of KS1] (KS2){}; 70 | \coordinate [below=1 of KS2] (KS3){}; 71 | \coordinate [right=1 of KS2] (KC1) {}; 72 | \coordinate [right=1 of KC1] (KC2) {}; 73 | \coordinate [above right=1 and 1 of KC2] (KT1){}; 74 | \coordinate [below=1 of KT1] (KT2){}; 75 | \coordinate [below=1 of KT2] (KT3){}; 76 | 77 | \begin{knot}[ 78 | % draft mode=crossings, 79 | % ignore endpoint intersections=false 80 | ] 81 | \strand[->] (KS1) 82 | to [out=0, in=135] (KC1) 83 | to [out=-45,in=-135] (KC2) 84 | to [out=45, in=180] (KT1); 85 | \strand[->] (KS2) 86 | to [out=0, in=180] (KC1) 87 | to [out=0, in=180] ([yshift=0cm]KC2) 88 | to [out=0, in=180] (KT2); 89 | \strand[->] (KS3) 90 | to [out=0, in=-135] (KC1) 91 | to [out=45, in=135] (KC2) 92 | to [out=-45, in=180] (KT3); 93 | \redraw{1}{(KC2)} 94 | %\flipcrossings{2}%1,3,5,2}%,6,4,2} 95 | \end{knot} 96 | 97 | \end{tikzpicture} 98 | %\] 99 | 100 | \end{document} 101 | -------------------------------------------------------------------------------- /examples/knotsarrows.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | %\url{https://tex.stackexchange.com/q/534491/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{decorations.markings,knots} 5 | 6 | \tikzset{% 7 | arrowat/.style={% 8 | postaction={decorate,decoration={ 9 | markings, 10 | mark=at position #1 with {\arrow[xshift=2pt]{>}}}} 11 | } 12 | } 13 | \begin{document} 14 | 15 | \begin{tikzpicture} 16 | \begin{knot} [ 17 | consider self intersections, 18 | ignore endpoint intersections=false, 19 | clip width=7, 20 | flip crossing=3, 21 | background colour=yellow, 22 | only when rendering/.style={ 23 | arrowat=0.8 24 | } 25 | ] 26 | \strand [thick] (0,0) 27 | to [out=180, in=270] (-1,1) 28 | to [out=90, in=180] (1,2.5) 29 | to [out=0, in=90] (3,1) 30 | to [out=270, in=0] (2,0) 31 | to [out=180, in=270] (-0.2,2.5) 32 | to [out=90, in=180] (1,3.8) 33 | to [out=0, in=90] (2.2,2.5) 34 | to [out=270, in=0] (0,0); 35 | \end{knot} 36 | \end{tikzpicture} 37 | 38 | \begin{tikzpicture} 39 | \begin{knot} [ 40 | consider self intersections, 41 | ignore endpoint intersections=false, 42 | clip width=7, 43 | flip crossing=3, 44 | ] 45 | \strand [thick, spath/save global=strand] 46 | (0,0) 47 | to [out=180, in=270] (-1,1) 48 | to [out=90, in=180] (1,2.5) 49 | to [out=0, in=90] (3,1) 50 | to [out=270, in=0] (2,0) 51 | to [out=180, in=270] (-0.2,2.5) 52 | to [out=90, in=180] (1,3.8) 53 | to [out=0, in=90] (2.2,2.5) 54 | to [out=270, in=0] (0,0) 55 | ; 56 | \end{knot} 57 | \draw[spath/restore=strand, arrowat=0.5]; 58 | \end{tikzpicture} 59 | 60 | \end{document} 61 | -------------------------------------------------------------------------------- /examples/localglobal.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \RequirePackage[enable-debug]{expl3} 3 | \ExplSyntaxOn 4 | \debug_on:n { check-declarations , deprecation } 5 | \ExplSyntaxOff 6 | \usepackage{tikz} 7 | \usetikzlibrary{knots} 8 | \begin{document} 9 | \begin{tikzpicture} 10 | \begin{knot}[ 11 | draft mode=strands 12 | ] 13 | \strand[red,thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 14 | \strand[blue,thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 15 | \end{knot} 16 | \end{tikzpicture} 17 | \end{document} 18 | -------------------------------------------------------------------------------- /examples/new_prime_knots.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage[scale=.9]{geometry} 3 | \usepackage{tikz} 4 | \usetikzlibrary{ 5 | spath3, 6 | intersections, 7 | hobby, 8 | external, 9 | decorations.pathreplacing, 10 | shapes.geometric, 11 | } 12 | 13 | \tikzset{ 14 | external/figure name=knot, 15 | external/prefix=knotdiagrams/new-, 16 | external/system call={pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource" && pdftoppm -png -singlefile "\image.pdf" "\image"}, 17 | } 18 | 19 | \tikzexternalize 20 | \tikzset{external/force remake=true} 21 | 22 | \let\origtikzsetnextfilename\tikzsetnextfilename 23 | \def\tikzsetnextfilename#1{% 24 | \origtikzsetnextfilename{#1}% 25 | \mysetlabel{#1}% 26 | } 27 | 28 | \newcommand{\mysetlabel}[1]{% 29 | \gdef\mynextlabel{#1}} 30 | 31 | \newcommand{\autolabel}{% 32 | \label{fig:\mynextlabel} 33 | \global\let\mynextlabel\relax 34 | } 35 | 36 | 37 | \tikzset{ 38 | use Hobby shortcut, 39 | every picture/.style={ 40 | execute at end picture={% 41 | \path ([shift={(-5pt,-5pt)}]current bounding box.south west) ([shift={(5pt,5pt)}]current bounding box.north east); 42 | } 43 | }, 44 | every spath component/.style={ultra thick, draw, red}, 45 | % every trefoil component/.style={ultra thick, draw, red}, 46 | } 47 | 48 | \begin{document} 49 | \begin{figure} 50 | \tikzsetnextfilename{unknot} 51 | \centering 52 | \begin{tikzpicture} 53 | \draw[ultra thick,red] (0,0) circle[radius=2cm]; 54 | \end{tikzpicture} 55 | \caption{Unknot} 56 | \autolabel 57 | \end{figure} 58 | 59 | \begin{figure} 60 | %% Trefoil 61 | %\tikzset{external/export next=false} 62 | \tikzsetnextfilename{trefoil} 63 | \centering 64 | \begin{tikzpicture} 65 | \path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); 66 | \tikzset{ 67 | spath/knot={trefoil}{8pt}{1,3,5}, 68 | } 69 | \end{tikzpicture} 70 | \caption{Trefoil} 71 | \autolabel 72 | \end{figure} 73 | 74 | \begin{figure} 75 | %% Figure 8 76 | \tikzsetnextfilename{figure8} 77 | %\tikzset{external/export next=false} 78 | \centering 79 | \begin{tikzpicture} 80 | \path[spath/save=figure8] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1) .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 81 | \tikzset{spath/knot={figure8}{8pt}{2,4,6,8}} 82 | \path (0,-.7); 83 | \end{tikzpicture} 84 | \caption{Figure 8} 85 | \autolabel 86 | \end{figure} 87 | 88 | \begin{figure} 89 | %% Cinquefoil 90 | \centering 91 | \tikzsetnextfilename{cinquefoil} 92 | %\tikzset{external/export next=false} 93 | %\tikzset{external/force remake} 94 | \begin{tikzpicture} 95 | \path[spath/save=cinquefoil] ([closed]90:2) foreach \k in {1,...,5} { .. (18+\k*144:1.5) .. (90+\k*144:2) } (90:2); 96 | \tikzset{spath/knot={cinquefoil}{8pt}{2,4,6,8,10}} 97 | \end{tikzpicture} 98 | \caption{Cinquefoil} 99 | \autolabel 100 | \end{figure} 101 | 102 | \begin{figure} 103 | %% 5_2 104 | \centering 105 | \tikzsetnextfilename{5-2} 106 | %\tikzset{external/export next=false} 107 | \begin{tikzpicture} 108 | \path[spath/save=5-2] ([closed]2,2) .. (1.8,0) .. (-2.3,-1) .. (.5,1) .. (-2,2) .. (-1.8,0) .. (2.3,-1) .. (-.5,1) .. (2,2); 109 | \tikzset{spath/knot={5-2}{8pt}{2,4,...,10}} 110 | \end{tikzpicture} 111 | \caption{\(5_2\)} 112 | \autolabel 113 | \end{figure} 114 | 115 | \begin{figure} 116 | %% 6_1 117 | \centering 118 | \tikzsetnextfilename{6-1} 119 | %\tikzset{external/export next=false} 120 | \begin{tikzpicture} 121 | \path[spath/save=6-1] ([closed]2,2) .. (2.5,0) .. (0,-4) .. (-2.5,0) .. (-2,2) .. (.5,1) .. (-3,-1) .. (0,-3) .. (3,-1) .. (-.5,1) .. (2,2); 122 | \tikzset{spath/knot={6-1}{8pt}{2,4,...,12}} 123 | \end{tikzpicture} 124 | \caption{\(6_1\)} 125 | \autolabel 126 | \end{figure} 127 | 128 | \begin{figure} 129 | %% 6_2 130 | \centering 131 | \tikzsetnextfilename{6-2} 132 | %\tikzset{external/export next=false} 133 | \begin{tikzpicture} 134 | \path[spath/save=6-2] ([closed]2,1) .. (1.8,0) .. (-2.3,-1) .. (.5,1) .. (0,4) .. (-.5,1) .. (2.3,-1) .. (-1.8,0) .. (-2,1) .. (2,1); 135 | \tikzset{spath/knot={6-2}{8pt}{2,4,...,12}} 136 | \end{tikzpicture} 137 | \caption{\(6_2\)} 138 | \autolabel 139 | \end{figure} 140 | 141 | \begin{figure} 142 | %% 6_3 143 | \centering 144 | \tikzsetnextfilename{6-3} 145 | %\tikzset{external/export next=false} 146 | \begin{tikzpicture} 147 | \path[spath/save=6-3,scale=1.3] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1.5) .. (-.5,2.5) .. (.5,2.5) .. (.5,.5) .. (-1,0) .. (0,-.5) .. (-.5,2) .. (-1.5,1) .. (0,0); 148 | \tikzset{ 149 | spath/knot={6-3}{8pt}{2,4,...,12} 150 | } 151 | \end{tikzpicture} 152 | \caption{\(6_3\)} 153 | \autolabel 154 | \end{figure} 155 | 156 | \begin{figure} 157 | %% 7_1 158 | \centering 159 | \tikzsetnextfilename{7-1} 160 | %\tikzset{external/export next=false} 161 | \begin{tikzpicture} 162 | \path[spath/save=7-1] ([closed]90:2) foreach \k in {1,...,7} { .. (90-360/7+\k*720/7:1.5) .. (90+\k*720/7:2) } (90:2); 163 | \tikzset{spath/knot={7-1}{8pt}{2,4,...,14}} 164 | \end{tikzpicture} 165 | \caption{\(7_1\)} 166 | \autolabel 167 | \end{figure} 168 | 169 | \begin{figure} 170 | %% 7_2 171 | \centering 172 | \tikzsetnextfilename{7-2} 173 | %\tikzset{external/export next=false} 174 | \begin{tikzpicture} 175 | \path[spath/save=7-2] ([closed].75,.5) .. (2.5,-.5) .. (3.5,.5) .. (-.5,2) .. (2,3) .. (.75,-.5) .. (-.75,.5) .. (-2.5,-.5) .. (-3.5,.5) .. (.5,2) .. (-2,3) .. (-.75,-.5); 176 | \tikzset{spath/knot={7-2}{8pt}{2,4,...,14}} 177 | \end{tikzpicture} 178 | \caption{\(7_2\)} 179 | \autolabel 180 | \end{figure} 181 | 182 | \begin{figure} 183 | %% 7_3 184 | \centering 185 | \tikzsetnextfilename{7-3} 186 | %\tikzset{external/export next=false} 187 | \begin{tikzpicture} 188 | \path[spath/save=7-3] ([closed]0,0) .. (1,.75) .. (2,4) .. (-.5,3.5) .. (.5,2) .. (-2,1) .. (-2,0) .. (0,.5) .. (2,0) .. (2,1) .. (-.5,2) .. (.5,3.5) .. (-2,4) .. (-1,.75); 189 | \tikzset{spath/knot={7-3}{8pt}{2,4,...,14}} 190 | \end{tikzpicture} 191 | \caption{\(7_3\)} 192 | \autolabel 193 | \end{figure} 194 | 195 | \begin{figure} 196 | %% 7_4 197 | \centering 198 | \tikzsetnextfilename{7-4} 199 | %\tikzset{external/export next=false} 200 | \begin{tikzpicture} 201 | \path[spath/save=7-4] ([closed]-2,2) .. (-2,3) .. (-1,3) .. (2,0) .. (-1,-3) .. (-2,-3) .. (-2,-2) .. (2,2) .. (2,3) .. (1,3) .. (-2,0) .. (1,-3) .. (2,-3) .. (2,-2) .. (-2,2); 202 | \tikzset{spath/knot={7-4}{8pt}{2,4,...,14}} 203 | \end{tikzpicture} 204 | \caption{\(7_4\)} 205 | \autolabel 206 | \end{figure} 207 | 208 | \begin{figure} 209 | %% 7_5 210 | \centering 211 | \tikzsetnextfilename{7-5} 212 | %\tikzset{external/export next=false} 213 | \begin{tikzpicture} 214 | \path[spath/save=7-5] ([closed]0,0) .. (.5,-.1) .. (-1,-3.5) .. (3,-6) .. (3,-7) .. (2,-7) .. (-3,-2) .. (0,-1) .. (3,-2) .. (-2,-7) .. (-3,-7) .. (-3,-6) .. (1,-3.5) .. (-.5,-.1) .. (0,0); 215 | \tikzset{spath/knot={7-5}{8pt}{2,4,...,14}} 216 | \end{tikzpicture} 217 | \caption{\(7_5\)} 218 | \autolabel 219 | \end{figure} 220 | 221 | \begin{figure} 222 | %% 7_6 223 | \centering 224 | \tikzsetnextfilename{7-6} 225 | %\tikzset{external/export next=false} 226 | \begin{tikzpicture} 227 | \path[spath/save=7-6] ([closed]0,5) .. (3,0) .. (-1,1) .. (4,5) .. (5,4) .. (4,3) .. (-2.6,5) .. (-4,5) .. (-4,3.6) .. (1,1) .. (-3,0); 228 | \tikzset{spath/knot={7-6}{8pt}{2,4,...,14}} 229 | \end{tikzpicture} 230 | \caption{\(7_6\)} 231 | \autolabel 232 | \end{figure} 233 | 234 | \begin{figure} 235 | %% 7_7 236 | \centering 237 | \tikzsetnextfilename{7-7} 238 | %\tikzset{external/export next=false} 239 | \begin{tikzpicture} 240 | \path[spath/save=7-7] ([closed]3.5,-2.5) .. (4.5,-1.5) .. (0,0) .. (-4.5,-1.5) .. (-3.5,-2.5) .. (1,2) .. (4,1) .. (.3,-3.85) .. (0,-4) .. (-.3,-3.85) .. (-4,1) .. (-1,2); 241 | \tikzset{spath/knot={7-7}{8pt}{2,4,...,14}} 242 | \end{tikzpicture} 243 | \caption{\(7_7\)} 244 | \autolabel 245 | \end{figure} 246 | 247 | 248 | \end{document} 249 | -------------------------------------------------------------------------------- /examples/nfoil.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage{tikz} 3 | \usetikzlibrary{knots,hobby} 4 | 5 | 6 | \begin{document} 7 | 8 | \begin{tikzpicture}[ 9 | use Hobby shortcut, 10 | every path/.style={ 11 | line width=1mm, 12 | white, 13 | double=red, 14 | double distance=.5mm 15 | } 16 | ] 17 | \def\nfoil{3} 18 | \draw ([closed]0,2) 19 | \foreach \k in {1,...,\nfoil} { 20 | .. ([blank=soft]90+360*\k/\nfoil-180/\nfoil:-.5) .. (90+360*\k/\nfoil:2) 21 | }; 22 | \draw[use previous Hobby path={invert soft blanks,disjoint}]; 23 | \end{tikzpicture} 24 | \end{document} 25 | -------------------------------------------------------------------------------- /examples/olympic.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | %\url{http://tex.stackexchange.com/q/323758/86} 3 | \usepackage{tikz} 4 | \usetikzlibrary{knots} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \definecolor{blue1}{RGB}{0,129,188} 8 | \definecolor{yellow1}{RGB}{252,177,49} 9 | \definecolor{black1}{RGB}{35,34,35} 10 | \definecolor{green1}{RGB}{0,157,87} 11 | \definecolor{red1}{RGB}{238,50,78} 12 | \begin{knot}[ 13 | clip width=1.4, 14 | clip radius=0.31cm 15 | ] 16 | \strand[line width=0.25cm,red1] (3,0) circle(1.25cm); 17 | \strand[line width=0.25cm,green1] (1.5,-1.375) circle(1.25cm); 18 | \strand[line width=0.25cm,black1] (0,0) circle(1.25cm); 19 | \strand[line width=0.25cm,yellow1] (-1.5,-1.375) circle(1.25cm); 20 | \strand[line width=0.25cm,blue1] (-3,0) circle(1.25cm); 21 | \flipcrossings{2,4,6,8} 22 | \end{knot} 23 | \end{tikzpicture} 24 | 25 | \vspace{2cm} 26 | 27 | \begin{tikzpicture} 28 | \definecolor{blue1}{RGB}{0,129,188} 29 | \definecolor{yellow1}{RGB}{252,177,49} 30 | \definecolor{black1}{RGB}{35,34,35} 31 | \definecolor{green1}{RGB}{0,157,87} 32 | \definecolor{red1}{RGB}{238,50,78} 33 | \begin{knot}[ 34 | clip width=1.5pt, 35 | name=olympic, 36 | ] 37 | \strand[line width=0.25cm,red1] (3,0) circle(1.25cm); 38 | \strand[line width=0.25cm,green1] (1.5,-1.375) circle(1.25cm); 39 | \strand[line width=0.25cm,black1] (0,0) circle(1.25cm); 40 | \strand[line width=0.25cm,yellow1] (-1.5,-1.375) circle(1.25cm); 41 | \strand[line width=0.25cm,blue1] (-3,0) circle(1.25cm); 42 | \flipcrossings{2,4,6,8} 43 | \redraw{2}{(olympic 3)} 44 | \end{knot} 45 | \end{tikzpicture} 46 | \end{document} 47 | -------------------------------------------------------------------------------- /examples/pentagram.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper, 12pt]{report} 2 | 3 | \pagestyle{empty} 4 | 5 | \usepackage{tikz} 6 | \usetikzlibrary{knots} 7 | 8 | 9 | \begin{document} 10 | 11 | \begin{tikzpicture} 12 | \def\R{5} % Radius of the pentagram 13 | \def\nbre{7} % To define a pentagram --> 7 = heptagram etc. 14 | \pgfmathsetmacro\nbremo{\nbre-1} 15 | \def\decalage{2} % nbre mod decalage != 0 16 | 17 | \begin{knot}[ 18 | %draft mode = crossings, 19 | %flip crossing/.list = {}, % Format {a,b} 20 | consider self intersections = true, 21 | only when rendering/.style = {black, double, double distance = 6pt} 22 | %only when rendering/.style = {white, line width = 3pt, double = black, double distance = 6pt} 23 | ] 24 | %\strand (90:\R) -- (-54:\R) -- (162:\R) -- (18:\R) -- (-126:\R) -- (90:\R) -- cycle; 25 | % VS 26 | %\strand (90:\R) -- (-54:\R) -- (162:\R) -- (18:\R) -- (-126:\R) -- cycle; 27 | \flipcrossings{2,4} % nbre = 5 28 | 29 | \strand (90:\R) \foreach \k in {1,...,\nbremo} {-- (90 - \decalage/\nbre*\k*360:\R)} -- cycle; % Automated path 30 | % !!! AJUSTER les flip crossing manuellement !!! 31 | \end{knot} 32 | \end{tikzpicture} 33 | 34 | \end{document} 35 | -------------------------------------------------------------------------------- /examples/prime_knots.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage[scale=.9]{geometry} 3 | \usepackage{tikz} 4 | \usetikzlibrary{ 5 | knots, 6 | hobby, 7 | external, 8 | decorations.pathreplacing, 9 | shapes.geometric, 10 | } 11 | 12 | \tikzset{ 13 | external/figure name=knot, 14 | external/prefix=knotdiagrams/, 15 | } 16 | 17 | \tikzexternalize 18 | 19 | \let\origtikzsetnextfilename\tikzsetnextfilename 20 | \def\tikzsetnextfilename#1{% 21 | \origtikzsetnextfilename{#1}% 22 | \mysetlabel{#1}% 23 | } 24 | 25 | \newcommand{\mysetlabel}[1]{% 26 | \gdef\mynextlabel{#1}} 27 | 28 | \newcommand{\autolabel}{% 29 | \label{fig:\mynextlabel} 30 | \global\let\mynextlabel\relax 31 | } 32 | 33 | 34 | \tikzset{ 35 | use Hobby shortcut, 36 | knot diagram/every strand/.append style={ 37 | ultra thick,red 38 | }, 39 | every picture/.style={ 40 | execute at end picture={% 41 | \path ([shift={(-5pt,-5pt)}]current bounding box.south west) ([shift={(5pt,5pt)}]current bounding box.north east); 42 | } 43 | }, 44 | show curve controls/.style={ 45 | postaction=decorate, 46 | decoration={show path construction, 47 | curveto code={ 48 | \draw [blue, dashed] 49 | (\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta) 50 | node [at end, draw, solid, red, inner sep=2pt]{}; 51 | \draw [blue, dashed] 52 | (\tikzinputsegmentsupportb) -- (\tikzinputsegmentlast) 53 | node [at start, draw, solid, red, inner sep=2pt]{} 54 | node [at end, fill, blue, ellipse, inner sep=2pt]{} 55 | ; 56 | } 57 | } 58 | }, 59 | show curve endpoints/.style={ 60 | postaction=decorate, 61 | decoration={show path construction, 62 | curveto code={ 63 | \node [fill, blue, ellipse, inner sep=2pt] at (\tikzinputsegmentlast) {} 64 | ; 65 | } 66 | } 67 | } 68 | } 69 | 70 | \begin{document} 71 | %\tikzset{external/force remake=true} 72 | \begin{figure} 73 | \tikzsetnextfilename{unknot} 74 | \centering 75 | \begin{tikzpicture} 76 | \draw[ultra thick,red] (0,0) circle[radius=2cm]; 77 | \end{tikzpicture} 78 | \caption{Unknot} 79 | \autolabel 80 | \end{figure} 81 | 82 | \begin{figure} 83 | %% Trefoil 84 | \tikzsetnextfilename{trefoil} 85 | \centering 86 | \begin{tikzpicture} 87 | \begin{knot}[ 88 | consider self intersections=true, 89 | % draft mode=crossings, 90 | flip crossing=2 91 | ] 92 | \strand ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); 93 | \end{knot} 94 | \end{tikzpicture} 95 | \caption{Trefoil} 96 | \autolabel 97 | \end{figure} 98 | 99 | \begin{figure} 100 | %% Figure 8 101 | \tikzsetnextfilename{figure8} 102 | %\tikzset{external/export next=false} 103 | \centering 104 | \begin{tikzpicture} 105 | \begin{knot}[ 106 | consider self intersections=true, 107 | % draft mode=crossings, 108 | ignore endpoint intersections=false, 109 | flip crossing=3 110 | ] 111 | \strand ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1) .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 112 | \end{knot} 113 | \path (0,-.7); 114 | \end{tikzpicture} 115 | \caption{Figure 8} 116 | \autolabel 117 | \end{figure} 118 | 119 | \begin{figure} 120 | %% Cinquefoil 121 | \centering 122 | \tikzsetnextfilename{cinquefoil} 123 | %\tikzset{external/export next=false} 124 | %\tikzset{external/force remake} 125 | \begin{tikzpicture} 126 | \begin{knot}[ 127 | consider self intersections=true, 128 | % draft mode=crossings, 129 | flip crossing/.list={2,4} 130 | ] 131 | \strand ([closed]90:2) foreach \k in {1,...,5} { .. (18+\k*144:1.5) .. (90+\k*144:2) } (90:2); 132 | \end{knot} 133 | \end{tikzpicture} 134 | \caption{Cinquefoil} 135 | \autolabel 136 | \end{figure} 137 | 138 | \begin{figure} 139 | %% 5_2 140 | \centering 141 | \tikzsetnextfilename{5-2} 142 | %\tikzset{external/export next=false} 143 | \begin{tikzpicture} 144 | \begin{knot}[ 145 | consider self intersections=true, 146 | % draft mode=crossings, 147 | ignore endpoint intersections=false, 148 | flip crossing/.list={6,4,2} 149 | ] 150 | \strand ([closed]2,2) .. (1.8,0) .. (-2.3,-1) .. (.5,1) .. (-2,2) .. (-1.8,0) .. (2.3,-1) .. (-.5,1) .. (2,2); 151 | \end{knot} 152 | \end{tikzpicture} 153 | \caption{\(5_2\)} 154 | \autolabel 155 | \end{figure} 156 | 157 | \begin{figure} 158 | %% 6_1 159 | \centering 160 | \tikzsetnextfilename{6-1} 161 | %\tikzset{external/export next=false} 162 | \begin{tikzpicture} 163 | \begin{knot}[ 164 | consider self intersections=true, 165 | % draft mode=crossings, 166 | ignore endpoint intersections=false, 167 | flip crossing/.list={7,4,2}, 168 | clip width=5, 169 | ] 170 | \strand ([closed]2,2) .. (2.5,0) .. (0,-4) .. (-2.5,0) .. (-2,2) .. (.5,1) .. (-3,-1) .. (0,-3) .. (3,-1) .. (-.5,1) .. (2,2); 171 | \end{knot} 172 | \end{tikzpicture} 173 | \caption{\(6_1\)} 174 | \autolabel 175 | \end{figure} 176 | 177 | \begin{figure} 178 | %% 6_2 179 | \centering 180 | \tikzsetnextfilename{6-2} 181 | %\tikzset{external/export next=false} 182 | \begin{tikzpicture} 183 | \begin{knot}[ 184 | consider self intersections=true, 185 | % draft mode=crossings, 186 | ignore endpoint intersections=false, 187 | flip crossing/.list={9,5,4}, 188 | clip width=5, 189 | ] 190 | \strand ([closed]2,1) .. (1.8,0) .. (-2.3,-1) .. (.5,1) .. (0,4) .. (-.5,1) .. (2.3,-1) .. (-1.8,0) .. (-2,1) .. (2,1); 191 | \end{knot} 192 | \end{tikzpicture} 193 | \caption{\(6_2\)} 194 | \autolabel 195 | \end{figure} 196 | 197 | \begin{figure} 198 | %% 6_3 199 | \centering 200 | \tikzsetnextfilename{6-3} 201 | %\tikzset{external/export next=false} 202 | \begin{tikzpicture} 203 | \begin{knot}[ 204 | consider self intersections=true, 205 | % draft mode=crossings, 206 | ignore endpoint intersections=false, 207 | flip crossing/.list={7,1,4}, 208 | clip width=5 209 | ] 210 | \strand[scale=1.3] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1.5) .. (-.5,2.5) .. (.5,2.5) .. (.5,.5) .. (-1,0) .. (0,-.5) .. (-.5,2) .. (-1.5,1) .. (0,0); 211 | \end{knot} 212 | \end{tikzpicture} 213 | \caption{\(6_3\)} 214 | \autolabel 215 | \end{figure} 216 | 217 | \begin{figure} 218 | %% 7_1 219 | \centering 220 | \tikzsetnextfilename{7-1} 221 | %\tikzset{external/export next=false} 222 | \begin{tikzpicture} 223 | \begin{knot}[ 224 | consider self intersections=true, 225 | % draft mode=crossings, 226 | flip crossing/.list={2,4,6} 227 | ] 228 | \strand ([closed]90:2) foreach \k in {1,...,7} { .. (90-360/7+\k*720/7:1.5) .. (90+\k*720/7:2) } (90:2); 229 | \end{knot} 230 | \end{tikzpicture} 231 | \caption{\(7_1\)} 232 | \autolabel 233 | \end{figure} 234 | 235 | \begin{figure} 236 | %% 7_2 237 | \centering 238 | \tikzsetnextfilename{7-2} 239 | %\tikzset{external/export next=false} 240 | \begin{tikzpicture} 241 | \begin{knot}[ 242 | consider self intersections=true, 243 | ignore endpoint intersections=false, 244 | % draft mode=crossings, 245 | only when rendering/.style={ 246 | % show curve endpoints 247 | }, 248 | flip crossing/.list={5,3,7} 249 | ] 250 | \strand ([closed].75,.5) .. (2.5,-.5) .. (3.5,.5) .. (-.5,2) .. (2,3) .. (.75,-.5) .. (-.75,.5) .. (-2.5,-.5) .. (-3.5,.5) .. (.5,2) .. (-2,3) .. (-.75,-.5); 251 | \end{knot} 252 | \end{tikzpicture} 253 | \caption{\(7_2\)} 254 | \autolabel 255 | \end{figure} 256 | 257 | \begin{figure} 258 | %% 7_3 259 | \centering 260 | \tikzsetnextfilename{7-3} 261 | %\tikzset{external/export next=false} 262 | \begin{tikzpicture} 263 | \begin{knot}[ 264 | consider self intersections=true, 265 | % ignore endpoint intersections=false, 266 | % draft mode=crossings, 267 | only when rendering/.style={ 268 | % show curve endpoints 269 | }, 270 | flip crossing/.list={5,1,3,7} 271 | ] 272 | \strand ([closed]0,0) .. (1,.75) .. (2,4) .. (-.5,3.5) .. (.5,2) .. (-2,1) .. (-2,0) .. (0,.5) .. (2,0) .. (2,1) .. (-.5,2) .. (.5,3.5) .. (-2,4) .. (-1,.75); 273 | \end{knot} 274 | \end{tikzpicture} 275 | \caption{\(7_3\)} 276 | \autolabel 277 | \end{figure} 278 | 279 | \begin{figure} 280 | %% 7_4 281 | \centering 282 | \tikzsetnextfilename{7-4} 283 | %\tikzset{external/export next=false} 284 | \begin{tikzpicture} 285 | \begin{knot}[ 286 | consider self intersections=true, 287 | % ignore endpoint intersections=false, 288 | % draft mode=crossings, 289 | only when rendering/.style={ 290 | % show curve endpoints 291 | }, 292 | flip crossing/.list={1,6,3} 293 | ] 294 | \strand ([closed]-2,2) .. (-2,3) .. (-1,3) .. (2,0) .. (-1,-3) .. (-2,-3) .. (-2,-2) .. (2,2) .. (2,3) .. (1,3) .. (-2,0) .. (1,-3) .. (2,-3) .. (2,-2) .. (-2,2); 295 | \end{knot} 296 | \end{tikzpicture} 297 | \caption{\(7_4\)} 298 | \autolabel 299 | \end{figure} 300 | 301 | \begin{figure} 302 | %% 7_5 303 | \centering 304 | \tikzsetnextfilename{7-5} 305 | %\tikzset{external/export next=false} 306 | \begin{tikzpicture} 307 | \begin{knot}[ 308 | consider self intersections=true, 309 | % ignore endpoint intersections=false, 310 | % draft mode=crossings, 311 | only when rendering/.style={ 312 | % show curve endpoints 313 | }, 314 | flip crossing/.list={2,6,3} 315 | ] 316 | \strand ([closed]0,0) .. (.5,-.1) .. (-1,-3.5) .. (3,-6) .. (3,-7) .. (2,-7) .. (-3,-2) .. (0,-1) .. (3,-2) .. (-2,-7) .. (-3,-7) .. (-3,-6) .. (1,-3.5) .. (-.5,-.1) .. (0,0); 317 | \end{knot} 318 | \end{tikzpicture} 319 | \caption{\(7_5\)} 320 | \autolabel 321 | \end{figure} 322 | 323 | \begin{figure} 324 | %% 7_6 325 | \centering 326 | \tikzsetnextfilename{7-6} 327 | %\tikzset{external/export next=false} 328 | \begin{tikzpicture} 329 | \begin{knot}[ 330 | consider self intersections=true, 331 | ignore endpoint intersections=false, 332 | % draft mode=crossings, 333 | only when rendering/.style={ 334 | % show curve endpoints 335 | }, 336 | flip crossing/.list={1,5,7,4} 337 | ] 338 | \strand ([closed]0,5) .. (3,0) .. (-1,1) .. (4,5) .. (5,4) .. (4,3) .. (-2.6,5) .. (-4,5) .. (-4,3.6) .. (1,1) .. (-3,0); 339 | \end{knot} 340 | \end{tikzpicture} 341 | \caption{\(7_6\)} 342 | \autolabel 343 | \end{figure} 344 | 345 | \begin{figure} 346 | %% 7_7 347 | \centering 348 | \tikzsetnextfilename{7-7} 349 | \tikzset{external/export next=false} 350 | \begin{tikzpicture} 351 | \begin{knot}[ 352 | consider self intersections=true, 353 | % ignore endpoint intersections=false, 354 | % draft mode=crossings, 355 | only when rendering/.style={ 356 | % show curve endpoints 357 | }, 358 | flip crossing/.list={1,3,5,6,7} 359 | ] 360 | \strand ([closed]3.5,-2.5) .. (4.5,-1.5) .. (0,0) .. (-4.5,-1.5) .. (-3.5,-2.5) .. (1,2) .. (4,1) .. (.3,-3.85) .. (0,-4) .. (-.3,-3.85) .. (-4,1) .. (-1,2); 361 | \end{knot} 362 | \end{tikzpicture} 363 | \caption{\(7_7\)} 364 | \autolabel 365 | \end{figure} 366 | 367 | 368 | \end{document} 369 | -------------------------------------------------------------------------------- /examples/renderpath.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{tikz} 4 | \usetikzlibrary{spath3} 5 | 6 | \ExplSyntaxOn 7 | 8 | \tikzset{ 9 | test~ style/.style={ 10 | draw=red, 11 | double=yellow, 12 | ultra~ thick, 13 | double~ distance=5pt, 14 | }, 15 | render~spath/.code={ 16 | \spath_tikz_path:nn { 17 | draw=red, 18 | double=yellow, 19 | ultra~ thick, 20 | double~distance=5pt 21 | } {#1} 22 | }, 23 | set~ spath/.code={ 24 | \spath_set_current_path:n { #1 } 25 | \spath_get:nnN {#1} {final point} \l__spath_tmpa_tl 26 | \tl_set:Nx \l__spath_tmpa_tl 27 | { 28 | \exp_not:c {tikz@lastx}=\tl_item:Nn \l__spath_tmpa_tl {1} 29 | \exp_not:c {tikz@lasty}=\tl_item:Nn \l__spath_tmpa_tl {2} 30 | \exp_not:c {tikz@lastxsaved}=\tl_item:Nn \l__spath_tmpa_tl {1} 31 | \exp_not:c {tikz@lastysaved}=\tl_item:Nn \l__spath_tmpa_tl {2} 32 | } 33 | \tl_use:N \l__spath_tmpa_tl 34 | }, 35 | } 36 | 37 | \ExplSyntaxOff 38 | 39 | \begin{document} 40 | 41 | \begin{tikzpicture} 42 | \path[spath/save=test] (0,0) -- (3,0); 43 | 44 | \tikzset{spath/render=test} 45 | 46 | \end{tikzpicture} 47 | \end{document} 48 | -------------------------------------------------------------------------------- /examples/smallcrossings.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper,11pt]{report} 2 | %\url{https://tex.stackexchange.com/q/478294/86} 3 | \usepackage{shellesc} 4 | \usepackage{graphicx,amssymb,amstext,amsmath} 5 | \usepackage{tikz} 6 | \usetikzlibrary{ 7 | decorations.pathreplacing, 8 | decorations.markings, 9 | hobby, 10 | knots, 11 | celtic, 12 | shapes.geometric, 13 | calc, 14 | external 15 | } 16 | 17 | \tikzexternalize 18 | 19 | \begin{document} 20 | 21 | \tikzset{ 22 | knot diagram/every strand/.append style={ 23 | line width=1.5pt,violet 24 | }, 25 | } 26 | 27 | \tikzset{ 28 | my style/.style={ 29 | dashed 30 | } 31 | } 32 | 33 | Demonstration of the problem: the clipping circles are big enough that the circle associated with the crossing between the violet line and the dashed grey line overlaps the problematic crossing. 34 | 35 | \tikzsetnextfilename{problem} 36 | \begin{tikzpicture}[scale=0.9, use Hobby shortcut, add arrow/.style={postaction={decorate}, decoration={ 37 | markings, 38 | mark=at position 0.25 with {\arrow[line width=1.5pt]{<}}, 39 | mark=at position 0.653 with {\arrow[line width=1.5pt]{<}}, 40 | mark=at position 0.75 with {\arrow[line width=1.5pt]{<}}}}] 41 | \begin{knot}[ 42 | consider self intersections=true, 43 | ignore endpoint intersections=false, 44 | flip crossing=3, 45 | background clip/.append style={ 46 | preaction={ 47 | fill=gray, 48 | fill opacity=.5, 49 | } 50 | }, 51 | rotate=180] 52 | \strand ([closed]0,0) .. (0.7,-0.7) .. (0,-1) .. (-1.7,0) .. (-1.5,2.2) .. (0,2.5) .. (.5,2) .. (-.5,1) [add arrow,violet] .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 53 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-1.2) -- (-0.7,-.9); 54 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-.75) -- (-0.7,2.5); 55 | \end{knot} 56 | \path (0,-.7); 57 | \end{tikzpicture} 58 | 59 | %--------------------------------------------------------------- 60 | 61 | Fix one: shrink the clipping circles using the \verb+clip radius+ key. 62 | 63 | \tikzsetnextfilename{fix-one} 64 | \begin{tikzpicture}[scale=0.9, use Hobby shortcut, add arrow/.style={postaction={decorate}, decoration={ 65 | markings, 66 | mark=at position 0.25 with {\arrow[line width=1.5pt]{<}}, 67 | mark=at position 0.653 with {\arrow[line width=1.5pt]{<}}, 68 | mark=at position 0.75 with {\arrow[line width=1.5pt]{<}}}}] 69 | \begin{knot}[ 70 | consider self intersections=true, 71 | ignore endpoint intersections=false, 72 | flip crossing=3, 73 | clip radius=3pt, 74 | background clip/.append style={ 75 | preaction={ 76 | fill=gray, 77 | fill opacity=.5, 78 | } 79 | }, 80 | rotate=180] 81 | \strand ([closed]0,0) .. (0.7,-0.7) .. (0,-1) .. (-1.7,0) .. (-1.5,2.2) .. (0,2.5) .. (.5,2) .. (-.5,1) [add arrow,violet] .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 82 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-1.2) -- (-0.7,-.9); 83 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-.75) -- (-0.7,2.5); 84 | \end{knot} 85 | \path (0,-.7); 86 | \end{tikzpicture} 87 | 88 | Fix two: the dashed grey lines don't appear to actually be anything to do with the knot, so draw them separately. 89 | This means that there aren't two crossings near to each other any more. 90 | 91 | \tikzsetnextfilename{fix-two} 92 | \begin{tikzpicture}[scale=0.9, use Hobby shortcut, add arrow/.style={postaction={decorate}, decoration={ 93 | markings, 94 | mark=at position 0.25 with {\arrow[line width=1.5pt]{<}}, 95 | mark=at position 0.653 with {\arrow[line width=1.5pt]{<}}, 96 | mark=at position 0.75 with {\arrow[line width=1.5pt]{<}}}}] 97 | \draw[ 98 | line width=1.5pt, 99 | my style, 100 | lightgray, 101 | rotate=180 102 | ] (-0.7,-1.2) -- (-0.7,2.5); 103 | \begin{knot}[ 104 | consider self intersections=true, 105 | ignore endpoint intersections=false, 106 | % flip crossing=6, 107 | rotate=180] 108 | \strand ([closed]0,0) .. (0.7,-0.7) .. (0,-1) .. (-1.7,0) .. (-1.5,2.2) .. (0,2.5) .. (.5,2) .. (-.5,1) [add arrow,violet] .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 109 | \end{knot} 110 | \path (0,-.7); 111 | \end{tikzpicture} 112 | 113 | Fix three: you specify a lot of \emph{nodes} in your Hobby path. 114 | If you aren't wedded to that specific path then reducing the number of nodes can simplify the knot algorithm. 115 | 116 | \tikzsetnextfilename{fix-three} 117 | \begin{tikzpicture}[scale=0.9, use Hobby shortcut, add arrow/.style={postaction={decorate}, decoration={ 118 | markings, 119 | mark=at position 0.2 with {\arrow[line width=1.5pt]{<}}, 120 | mark=at position 0.28 with {\arrow[line width=1.5pt]{<}}, 121 | mark=at position 0.8 with {\arrow[line width=1.5pt]{<}}}}] 122 | \draw[ 123 | line width=1.5pt, 124 | my style, 125 | lightgray, 126 | rotate=180 127 | ] (-0.7,-2.2) -- (-0.7,3.5); 128 | \begin{knot}[ 129 | consider self intersections=true, 130 | end tolerance=3pt, 131 | flip crossing=4, 132 | rotate=180] 133 | \strand ([closed].5,2) [add arrow,violet] .. (-.5,1) .. (.3,-.5) .. (-.3,-.5) .. (.5,1) .. ([tension=3]-1.5,1) .. (.7,-1) .. (-2,1); 134 | \end{knot} 135 | \path (0,-.7); 136 | \end{tikzpicture} 137 | 138 | 139 | \tikzsetnextfilename{large-scale} 140 | \begin{tikzpicture}[scale=2, use Hobby shortcut, add arrow/.style={postaction={decorate}, decoration={ 141 | markings, 142 | mark=at position 0.25 with {\arrow[line width=1.5pt]{<}}, 143 | mark=at position 0.653 with {\arrow[line width=1.5pt]{<}}, 144 | mark=at position 0.75 with {\arrow[line width=1.5pt]{<}}}}] 145 | \begin{knot}[ 146 | consider self intersections=true, 147 | ignore endpoint intersections=false, 148 | flip crossing=3, 149 | rotate=180] 150 | \strand ([closed]0,0) .. (0.7,-0.7) .. (0,-1) .. (-1.7,0) .. (-1.5,2.2) .. (0,2.5) .. (.5,2) .. (-.5,1) [add arrow,violet] .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 151 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-1.2) -- (-0.7,-.9); 152 | \strand[knot diagram/only when rendering/.style={my style}, lightgray] (-0.7,-.75) -- (-0.7,2.5); 153 | \end{knot} 154 | \path (0,-.7); 155 | \end{tikzpicture} 156 | 157 | \end{document} 158 | -------------------------------------------------------------------------------- /examples/spath3_test.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | \immediate\write18{cd ..; tex spath3_code.dtx} 3 | \documentclass{article} 4 | \usepackage[svgnames]{xcolor} 5 | \RequirePackage[enable-debug]{expl3} 6 | \ExplSyntaxOn 7 | \debug_on:n {check-declarations, deprecation} 8 | \ExplSyntaxOff 9 | \usepackage{tabularx} 10 | \usepackage{tikz} 11 | \usetikzlibrary{ 12 | spath3, 13 | intersections, 14 | patterns, 15 | hobby} 16 | 17 | \makeatletter 18 | \def\showpath{% 19 | \def\pgfqpoint##1##2{(##1, ##2)}% 20 | \def\pgfsyssoftpath@movetotoken##1##2{% 21 | M\{##1\}\{##2\} 22 | }% 23 | \def\pgfsyssoftpath@linetotoken##1##2{% 24 | L\{##1\}\{##2\} 25 | }% 26 | \def\pgfsyssoftpath@curvetotoken##1##2{% 27 | C\{##1\}\{##2\} 28 | }% 29 | \def\pgfsyssoftpath@curvetosupportatoken##1##2{% 30 | Ca\{##1\}\{##2\} 31 | }% 32 | \def\pgfsyssoftpath@curvetosupportbtoken##1##2{% 33 | Cb\{##1\}\{##2\} 34 | }% 35 | \def\pgfsyssoftpath@closepathtoken##1##2{% 36 | Z\{##1\}\{##2\} 37 | }% 38 | } 39 | \makeatother 40 | 41 | % Note: this was for a previous version and doesn't work with the 42 | % current one, but it might be useful to adapt it to the current 43 | % version so I'm keeping it around to remember what it originally 44 | % looked like. 45 | 46 | \newcommand\displaypath[1]{% 47 | 48 | Displaying path information for: #1 49 | 50 | \begin{tabularx}{\textwidth}{r@{:\hskip\arraycolsep}>{\raggedright\arraybackslash}X} 51 | Length & \SPathInfo{#1}{length} \\ 52 | Real length & \SPathInfo{#1}{reallength} \\ 53 | Number of components & \SPathInfo{#1}{numberofcomponents} \\ 54 | Initial point & \showpath\SPathInfoInto{#1}{initialpoint}{\stuff}\expandafter\pgfqpoint\stuff \\ 55 | Final point & \showpath\SPathInfoInto{#1}{finalpoint}{\stuff}\expandafter\pgfqpoint\stuff \\ 56 | Initial action & \texttt{\showpath\SPathInfo{#1}{initialaction}} \\ 57 | Final action & \texttt{\showpath\SPathInfo{#1}{finalaction}} \\ 58 | Path & \texttt{\showpath\SPathInfo{#1}{path}} \\ 59 | Reverse path & \texttt{\showpath\SPathInfo{#1}{reversepath}} \\ 60 | Min bb & \showpath\SPathInfoInto{#1}{minbb}{\stuff}\expandafter\pgfqpoint\stuff \\ 61 | Max bb & \showpath\SPathInfoInto{#1}{maxbb}{\stuff}\expandafter\pgfqpoint\stuff 62 | \end{tabularx}% 63 | } 64 | 65 | \makeatletter 66 | \tikzset{ 67 | show last coords/.code={ 68 | \edef\tikz@last@coords{(% 69 | \the\tikz@lastx, 70 | \the\tikz@lasty), (% 71 | \the\tikz@lastxsaved, 72 | \the\tikz@lastysaved), (% 73 | \the\tikz@lastmovetox, 74 | \the\tikz@lastmovetoy)% 75 | }% 76 | \show\tikz@last@coords 77 | }, 78 | show tikz timer/.code={ 79 | \show\tikz@timer 80 | } 81 | } 82 | \makeatother 83 | 84 | \ExplSyntaxOn 85 | 86 | \DeclareDocumentCommand\SPathPoint {m m} 87 | { 88 | \spath_get_point_at:nnN {#1} {#2} \l__tmpa_tl 89 | \tl_show:N \l__tmpa_tl 90 | } 91 | 92 | \ExplSyntaxOff 93 | \begin{document} 94 | 95 | \begin{tikzpicture} 96 | \path[spath/save=a] (0,0) -- (2,1); 97 | \begin{scope}[xshift=3cm,rotate=90] 98 | \draw[spath/use=a,orange,line width=4mm]; 99 | \draw[spath/use={a, transform={xshift=3cm, rotate=90}},green, line width=4mm]; 100 | \draw[spath/use={a,use current transformation},line width=2mm]; 101 | \draw[line width=1mm,blue] (0,0) -- (2,1); 102 | \end{scope} 103 | \end{tikzpicture} 104 | 105 | 106 | 107 | \begin{tikzpicture} 108 | \coordinate (a) at (-1,0.5); 109 | \coordinate (b) at (8,0.5); 110 | \coordinate (c) at (3,-0.5); 111 | \path[spath/save=sine] 112 | (-1.57,-1) 113 | cos ++(1.57,1) 114 | sin ++(1.57,1) 115 | cos ++(1.57,-1) 116 | sin ++(1.57,-1) 117 | cos ++(1.57,1) 118 | sin ++(1.57,1); 119 | \path[spath/save=over] (a) -- (c) |- (b); 120 | 121 | \path[spath/save=arc] (0,0) arc[radius=1cm, start angle=180, delta angle=-180]; 122 | 123 | \tikzset{ 124 | spath/split at intersections with={over}{sine}, 125 | spath/insert gaps after components={over}{8pt}, 126 | spath/join components upright with={over}{arc}, 127 | spath/split at intersections with={sine}{over}, 128 | spath/insert gaps after components={sine}{4pt}, 129 | } 130 | 131 | \draw[spath/use=sine]; 132 | \draw[spath/use=over]; 133 | \end{tikzpicture} 134 | 135 | 136 | \begin{tikzpicture} 137 | \draw[line width=5pt,orange] (0,0) -- (2,0) to[out=90,in=90] (-.5,0); 138 | \draw[ultra thick] (0,0) -- (2,0) to[out=90,in=90] (-.5,0) 139 | [spath/adjust and close=current] 140 | ; 141 | \end{tikzpicture} 142 | 143 | 144 | \begin{tikzpicture} 145 | \path[spath/save=abc,draw=green, line width=5pt] (0,0) to[bend right] (1,0); 146 | \path[spath/save=def,draw=red, line width=5pt] 147 | (0,0) -- ++(1,0) 148 | ++(1,0) -- ++(1,0) 149 | ++(1,0) -- ++(1,0) 150 | ++(0,1) -- ++(-1,0) 151 | ++(-1,0) -- ++(-1,0) 152 | ++(-1,0) -- ++(-1,0) 153 | [ 154 | spath/join components with={current}{abc}, 155 | ] 156 | ; 157 | 158 | \path[spath/save=ghi, draw, blue, line width=5pt] (1.5,-1) -- ++(0,3) -- ++(2,0) -- ++(0,-3); 159 | 160 | \tikzset{ 161 | spath/split at intersections={def}{ghi}, 162 | } 163 | 164 | \draw[ultra thick, spath/use=def]; 165 | 166 | \path[spath/save=jkl, draw=purple, line width=5pt] (0,-3) -- ++(1,1) -- ++(1,-1) -- ++(0,1) -- ++(-1,-1) -- ++(-1,1); 167 | 168 | \tikzset{ 169 | spath/split at self intersections=jkl, 170 | spath/insert gaps after components={jkl}{5pt}{1,3}, 171 | spath/join components={jkl}{3,5}, 172 | spath/get components of={jkl}\Cpts 173 | } 174 | 175 | \tikzset{ 176 | every jkl component/.style={draw, ultra thick}, 177 | jkl component 1/.style={white}, 178 | jkl component 3/.style={white}, 179 | spath/render components=jkl 180 | } 181 | 182 | \draw[spath/transform to={jkl}{.25}] (0,0) -- +(0,1) node[above] {A}; 183 | \draw[spath/upright transform to={jkl}{.75}] (0,0) -- +(0,1) node[below] {B}; 184 | 185 | \draw[red] (spath cs:jkl .5) circle[radius=3pt]; 186 | 187 | \end{tikzpicture} 188 | 189 | 190 | 191 | % Checking errors 192 | \begin{tikzpicture} 193 | \foreach \pth in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} 194 | { 195 | \path[spath/save=\pth] (0,0); 196 | } 197 | \foreach \pth in {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z} 198 | { 199 | \path[spath/save=\pth] (0,0); 200 | } 201 | 202 | \tikzset{ 203 | spath/.cd, 204 | clone=aA, 205 | clone global=bB, 206 | save to aux=c, 207 | export to svg=d, 208 | use=e, 209 | restore=f, 210 | restore reverse=g, 211 | append=h, 212 | append no move=i, 213 | append reverse=j, 214 | append reverse no move=k, 215 | insert=l, 216 | insert reverse=m, 217 | show=n, 218 | join with=oO, 219 | spot weld=p, 220 | spot weld globally=q, 221 | reverse=r, 222 | reverse globally=s, 223 | span=t{(0,0)}{(2,3)}, 224 | span global=u{(0,0)}{(2,3)}, 225 | splice=vVw, 226 | splice global=xXy, 227 | join components with=zZ, 228 | join components globally with=aA, 229 | join components upright with=bB, 230 | join components globally upright with=cC, 231 | close=d, 232 | close globally=e, 233 | close with=fF, 234 | close globally with=gG, 235 | shorten at end=h{5pt}, 236 | shorten at start=i{5pt}, 237 | shorten at both ends=j{5pt}, 238 | shorten globally at end=k{5pt}, 239 | shorten globally at start=l{5pt}, 240 | shorten globally at both ends=m{5pt}, 241 | translate=n{5pt}{5pt}, 242 | translate globally=o{5pt}{5pt}, 243 | normalise=p, 244 | normalise globally=q, 245 | transform=r{shift={(3,2)}}, 246 | transform globally=s{shift={(3,2)}}, 247 | split at intersections with=tT, 248 | split globally at intersections with=uU, 249 | split at intersections=vV, 250 | split globally at intersections=wW, 251 | split at self intersections=x, 252 | split globally at self intersections=y, 253 | get components of=z\cpts, 254 | get components of globally=a\cpts, 255 | render components=b, 256 | insert gaps after components=c{5pt}, 257 | insert gaps globally after components=d{5pt}, 258 | join components=e, 259 | join components globally=f, 260 | remove empty components=g, 261 | remove empty components globally=h, 262 | replace lines=i, 263 | replace lines globally=j, 264 | remove components=k{2}, 265 | remove components globally=l{2}, 266 | maybe spot weld=m, 267 | maybe spot weld globally=n, 268 | transform to=o{1.5}, 269 | upright transform to=p{1.5}, 270 | } 271 | \end{tikzpicture} 272 | 273 | \begin{tikzpicture} 274 | 275 | \path[spath/save=zig] (0,0) |- ++(1,1) +(0,0) -| ++(1,-1); 276 | 277 | \draw (0,-2) -- ++(0,2) [spath/use={zig,weld}] -- cycle; 278 | 279 | \path[spath/save=zag] (3,0) |- ++(1,1) -| ++(1,-1); 280 | 281 | \draw (3,-2) -- ++(0,2) [spath/use={zag,weld}] -- cycle; 282 | \end{tikzpicture} 283 | 284 | 285 | 286 | \begin{tikzpicture} 287 | \begin{scope} 288 | \draw[spath/save=a] (0,0) -- +(2,0); 289 | \end{scope} 290 | 291 | \draw[spath/save=b] (0,-1) -- +(0,2); 292 | \tikzset{ 293 | spath/split at intersections with=ab 294 | } 295 | \end{tikzpicture} 296 | 297 | 298 | \begin{tikzpicture}[ 299 | use Hobby shortcut, 300 | knot/.style 2 args={ 301 | every #1 component/.style={ultra thick, draw, red}, 302 | #1 component 1/.style={blue}, 303 | spath/.cd, 304 | split at self intersections=#1, 305 | remove empty components=#1, 306 | insert gaps after components={#1}{8pt}{#2}, 307 | spot weld=#1, 308 | render components=#1 309 | } 310 | ] 311 | \path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); 312 | \tikzset{knot={trefoil}{1,3,5}} 313 | \end{tikzpicture} 314 | 315 | 316 | 317 | \tikzset{ 318 | test/.code 2 args={ 319 | \message{Got: #1, #2} 320 | }, 321 | test=abc, 322 | test={a}{b}{c}, 323 | test={a}{bc} 324 | } 325 | 326 | \begin{tikzpicture} 327 | \path[ 328 | draw=orange, 329 | ultra thick, 330 | spath/save=arc] (0,0) arc[radius=1,start angle=180, end angle=0]; 331 | 332 | \path[ 333 | draw=cyan, 334 | ultra thick, 335 | spath/save=start] 336 | (0,1) -- ++(1,1) 337 | ++(1,0) -- ++(1,-1) 338 | ++(0,-1) -- ++(-1,-1) 339 | ++(-1,0) -- ++(-1,1) 340 | ; 341 | 342 | \tikzset{ 343 | spath/join components with={start}{arc}, 344 | spath/close with={start}{arc}, 345 | } 346 | 347 | \draw[spath/restore=start]; 348 | \end{tikzpicture} 349 | 350 | \begin{tikzpicture} 351 | \path[ 352 | draw=orange, 353 | spath/save=arc] (0,0) arc[radius=1,start angle=180, end angle=0]; 354 | 355 | \path[ 356 | draw=cyan, 357 | line width=5pt, 358 | spath/save=start] 359 | (0,1) -- ++(1,1) 360 | ++(1,0) -- ++(1,-1) 361 | ++(0,-1) -- ++(-1,-1) 362 | ++(-1,0) -- ++(-1,1) 363 | ; 364 | 365 | \fill[magenta] 366 | (0,1) circle[radius=6pt] 367 | ; 368 | 369 | \tikzset{ 370 | spath/join components with={start}{arc}{1,2}, 371 | } 372 | 373 | \draw[line width=2pt, spath/restore=start]; 374 | \end{tikzpicture} 375 | 376 | 377 | 378 | 379 | \begin{tikzpicture} 380 | \path[spath/save=ab] (0,0) to[out=0,in=180] +(3,1); 381 | \path[spath/save=cd] (0,2) to[out=90,in=-90] +(3,1); 382 | \tikzset{ 383 | spath/join with={ab}{cd, reverse, move, weld, transform={scale=2,rotate=90}}, 384 | spath/show=ab, 385 | } 386 | \draw[ 387 | orange, 388 | ultra thick, 389 | spath/restore=ab 390 | ]; 391 | \end{tikzpicture} 392 | 393 | 394 | \begin{tikzpicture}[scale=2] 395 | \path[spath/save=ab] (0,1) -- ++(2,0); 396 | \draw[spath/restore=ab] node[auto,pos=.5] {ab} node[auto,pos=.75] {bc}; 397 | \draw[spath/transform={ab}{scale=3},spath/restore=ab] node[auto,pos=.5] {ab}; 398 | \end{tikzpicture} 399 | 400 | 401 | \begin{tikzpicture} 402 | \draw[orange, ultra thick, spath/save=sq] 403 | (0,0) -- ++(1,0) 404 | +(0,0) -- ++(0,1) 405 | +(0,0) -- ++(-1,0) 406 | +(0,0) -- ++(0,-1) 407 | ; 408 | 409 | \tikzset{ 410 | spath/remove components={sq}{1,3}, 411 | spath/show=sq 412 | } 413 | 414 | \draw[spath/restore=sq]; 415 | \end{tikzpicture} 416 | 417 | 418 | \begin{tikzpicture} 419 | \path[draw=orange,ultra thick,spath/save=a] (3,2) -- ++(1,1) to[out=90,in=-90] ++(3,0); 420 | 421 | \tikzset{ 422 | spath/span={a}{(4,5)}{(7,1)} 423 | } 424 | 425 | \fill 426 | (4,5) circle[radius=3pt] 427 | (7,1) circle[radius=3pt] 428 | ; 429 | 430 | \draw[spath/restore=a]; 431 | 432 | \draw (0,0) -- +(1,0) to[spath/to={a}] node[pos=.6,auto] {node} ++(2,-1) -- +(0,1); 433 | \fill 434 | (0,0) circle[radius=3pt] 435 | +(1,0) circle[radius=3pt] 436 | ++(2,-1) circle[radius=3pt] 437 | +(0,1) circle[radius=3pt] 438 | ; 439 | \end{tikzpicture} 440 | 441 | \begin{tikzpicture} 442 | \path[draw=orange,ultra thick,spath/save=a] (3,2) -- ++(1,1) to[out=90,in=-90] ++(3,0); 443 | \tikzset{ 444 | spath/show=a, 445 | spath/normalise=a, 446 | spath/show=a, 447 | } 448 | 449 | \draw[spath/transform={a}{scale=28},spath/restore=a]; 450 | \end{tikzpicture} 451 | 452 | 453 | \begin{tikzpicture} 454 | \fill[red] (0.01869pt, 54.94537pt) circle[radius=8pt]; 455 | 456 | 457 | \draw[ultra thick,spath/save=short] 458 | (-0.05162pt, 16.03508pt) 459 | .. controls (5.78798pt, 19.31158pt) 460 | and (11.75685pt, 22.57562pt) 461 | .. (14.22594pt, 28.45274pt) 462 | .. controls (17.33452pt, 35.85257pt) 463 | and (15.03658pt, 43.39893pt) 464 | .. (9.5325pt, 48.87686pt) 465 | .. controls (6.97835pt, 51.41888pt) 466 | and (3.73378pt, 53.5155pt) 467 | .. (0.01869pt, 54.94537pt) 468 | ; 469 | 470 | \draw[spath/transform to={short}{.3333}] (0,0) +(0,.3) -- +(0,-.3); 471 | \draw[spath/transform to={short}{.6666}] (0,0) +(0,.3) -- +(0,-.3); 472 | 473 | \draw[white, 474 | spath/shorten at end={short}{8pt}, 475 | spath/show=short, 476 | spath/restore=short]; 477 | 478 | \draw[cyan] (0.01869pt, 54.94537pt) -- 479 | (3.73378pt, 53.5155pt) 480 | (9.5325pt, 48.87686pt) 481 | -- (6.97835pt, 51.41888pt) 482 | ; 483 | 484 | \end{tikzpicture} 485 | 486 | 487 | \begin{tikzpicture}[ 488 | every spath component/.style={ultra thick, draw, red}, 489 | use Hobby shortcut, 490 | ] 491 | \path[spath/save=figure8] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1) .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 492 | \fill (0,0) circle[radius=2pt] 493 | (1.5,1) circle[radius=2pt] 494 | (.5,2) circle[radius=2pt] 495 | (-.5,1) circle[radius=2pt] 496 | (.5,0) circle[radius=2pt] 497 | (0,-.5) circle[radius=2pt] 498 | (-.5,0) circle[radius=2pt] 499 | (.5,1) circle[radius=2pt] 500 | (-.5,2) circle[radius=2pt] 501 | (-1.5,1) circle[radius=2pt] 502 | ; 503 | \tikzset{ 504 | spath/draft mode=true, 505 | spath/knot={figure8}{8pt}{},%2,4,6,8}, 506 | spath/get components of={figure8}\cpts, 507 | spath/show=\getComponentOf\cpts{6}, 508 | spath/insert gaps after components={figure8}{8pt}{6}, 509 | spath/get components of={figure8}\ncpts, 510 | spath/show=\getComponentOf\ncpts{6}, 511 | } 512 | \draw[ultra thick,spath/restore=\getComponentOf\cpts{6}]; 513 | \draw[white,spath/restore=\getComponentOf\ncpts{6}]; 514 | \path (0,-.7); 515 | \end{tikzpicture} 516 | 517 | 518 | \begin{tikzpicture} 519 | \path[spath/save=g,draw] 520 | (0,0) -- ++(1,0) 521 | ++(0,0) -- ++(1,0) 522 | ++(0,0) -- ++(1,0) 523 | ++(0,0) -- ++(1,0) 524 | ++(0,0) -- ++(1,0) 525 | ; 526 | \tikzset{spath/get components of={g}\cpts} 527 | 528 | \draw[line width=3pt, orange, spath/restore=\getComponentOf{\cpts}{3}]; 529 | \draw[line width=3pt, magenta, spath/restore=\getComponentOf{\cpts}{4}]; 530 | \end{tikzpicture} 531 | 532 | 533 | \begin{tikzpicture} 534 | \path[spath/save=a] (0,0) -- node[pos=.5,auto] {\(a\)} 535 | ++(2,0) to[out=0,in=-90] node[pos=.5,auto] {\(b\)} ++(2,2) to[out=90,in=0] node[pos=.5,auto] {\(c\)} ++(-2,2) 536 | ; 537 | \draw[spath/restore=a] 538 | node[pos=.16,auto,swap] {\(a\)} 539 | node[pos=.5,auto,swap,sloped] {\(b\)} 540 | node[pos=.84,auto,swap,sloped,allow upside down] {\(c\)} 541 | ; 542 | 543 | \draw (0,-1) -- ++(3,-1) [spath/append=a] 544 | node[pos=.16,auto,swap] {\(a\)} 545 | node[pos=.5,auto,swap,sloped] {\(b\)} 546 | node[pos=.84,auto,swap,sloped,allow upside down] {\(c\)} 547 | ; 548 | \end{tikzpicture} 549 | 550 | 551 | \begin{tikzpicture} 552 | \begin{scope}[scale=.5, rotate=30, xscale=2, shift={(3,-1)}] 553 | \path 554 | (0,0) node[circle,fill] {} 555 | (2,1) node[circle,fill] {} 556 | ++(2,0) node[circle,fill] {} 557 | +(0,1) node[circle,fill] {} 558 | +(0,3) node[circle,fill] {} 559 | +(1,0) node[circle,fill] {} 560 | ; 561 | \draw[spath/save global=b, line width=5pt, orange] (2,1) -- ++(1,1) -- +(1,-1) [show last coords]; 562 | \end{scope} 563 | \path 564 | (spath cs:b 1) node[circle,fill=blue] {} 565 | +(0,1) node[circle,fill=blue] {} 566 | +(0,3) node[circle,fill=blue] {} 567 | +(1,0) node[circle,fill=blue] {} 568 | ; 569 | 570 | \tikzset{spath/show=b} 571 | \draw[spath/restore=b,show last coords] -- +(0,1); 572 | \tikzset{spath/show=b} 573 | \begin{scope}[scale=3] 574 | \draw[spath/restore=b,show last coords] -- +(0,1); 575 | \end{scope} 576 | \draw[spath/restore=b] to[out=-90,in=-90] +(1,0); 577 | \draw[spath/restore=b] to[out=-90,in=-90] cycle; 578 | \end{tikzpicture} 579 | 580 | 581 | \begin{tikzpicture}[use Hobby shortcut] 582 | \path[spath/save=figure8] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1) .. (.5,0) .. (0,-.5) .. (-.5,0) .. (.5,1) .. (-.5,2) .. (-1.5,1) .. (0,0); 583 | \tikzset{spath/knot={figure8}{8pt}{2,4,6,8}} 584 | \path (0,-.7); 585 | \end{tikzpicture} 586 | 587 | 588 | \begin{tikzpicture} 589 | \path[spath/save=curve,draw] (0,0) to[out=-90,in=180] (2,0) to[out=0,in=90] (4,0) to[out=-90,in=-90] (2,0) to[out=90,in=90] cycle; 590 | \tikzset{ 591 | every spath component/.style={draw, ultra thick}, 592 | curve component 1/.style={blue}, 593 | curve component 2/.style={green}, 594 | curve component 3/.style={orange}, 595 | curve component 4/.style={magenta}, 596 | curve component 5/.style={cyan}, 597 | curve component 6/.style={green!50!black}, 598 | curve component 7/.style={yellow!50!black}, 599 | curve component 8/.style={red!50!black}, 600 | curve component 9/.style={blue!50!black}, 601 | spath/draft mode=true, 602 | spath/knot={curve}{8pt}{}, 603 | } 604 | \end{tikzpicture} 605 | 606 | \begin{tikzpicture}[use Hobby shortcut] 607 | \path[spath/save=6-3,scale=1.3] ([closed]0,0) .. (1.5,1) .. (.5,2) .. (-.5,1.5) .. (-.5,2.5) .. (.5,2.5) .. (.5,.5) .. (-1,0) .. (0,-.5) .. (-.5,2) .. (-1.5,1) .. (0,0); 608 | \tikzset{ 609 | every spath component/.style={draw,ultra thick}, 610 | 6-3 component 1/.style={blue}, 611 | 6-3 component 2/.style={green}, 612 | 6-3 component 3/.style={orange}, 613 | 6-3 component 4/.style={magenta}, 614 | 6-3 component 5/.style={cyan}, 615 | 6-3 component 6/.style={green!50!black}, 616 | 6-3 component 7/.style={yellow!50!black}, 617 | 6-3 component 8/.style={red!50!black}, 618 | 6-3 component 9/.style={blue!50!black}, 619 | 6-3 component 10/.style={Fuchsia}, 620 | 6-3 component 11/.style={SeaGreen}, 621 | 6-3 component 12/.style={DarkSlateBlue}, 622 | spath/draft mode=true, 623 | spath/knot={6-3}{8pt}{},%2,4,...,12} 624 | } 625 | \end{tikzpicture} 626 | 627 | 628 | \begin{tikzpicture} 629 | \draw[spath/save=oval] (0,0) to[out=0,in=0] (0,2) to[out=180,in=180] (0,0); 630 | \foreach \k in {0,...,9} { 631 | \node[transform shape, allow upside down=false, spath/transform to={oval}{0.\k}, rotate=-90,right] {along}; 632 | } 633 | \begin{scope}[xshift = 3cm] 634 | \draw[spath/save=soval] (0,0) to[out=0,in=0] (0,2) to[out=180,in=180] (0,0); 635 | \foreach \k in {0,...,9} { 636 | \node[transform shape, spath/upright transform to={soval}{0.\k}] {q}; 637 | } 638 | \begin{scope}[xshift = 3cm] 639 | \draw[spath/save=soval] (0,0) to[out=0,in=0] (0,2) to[out=180,in=180] (0,0); 640 | \foreach \k in {0,...,9} { 641 | \node[transform shape, spath/transform to={soval}{0.\k}] {q}; 642 | } 643 | \end{scope} 644 | \end{scope} 645 | \end{tikzpicture} 646 | 647 | 648 | 649 | \begin{tikzpicture} 650 | \draw[spath/save=oval] (0,0) to[out=0,in=0] (0,2) +(-1,0) to[out=180,in=180] (0,0); 651 | \tikzset{spath/spot weld=oval} 652 | \end{tikzpicture} 653 | 654 | \begin{tikzpicture} 655 | \draw[spath/save=tpath] (0,0) rectangle +(1,1); 656 | \draw[rotate=45, xscale=2, yscale=3, ultra thick, red] (0,0) rectangle +(1,1); 657 | \draw[ 658 | spath/transform={tpath}{rotate=45, xscale=2, yscale=3}, 659 | spath/restore={tpath}]; 660 | \end{tikzpicture} 661 | 662 | \begin{tikzpicture} 663 | \path[spath/save=rpath] (0,0) to[out=30,in=150] (1,1); 664 | \foreach \k in {1,...,9} { 665 | \fill[green] (spath cs:rpath 0.\k) circle[radius=3pt]; 666 | \node[above left] at (spath cs:rpath 0.\k) {\(0.\k\)}; 667 | } 668 | \fill[green] (2,2) circle[radius=3pt]; 669 | \draw[blue, spath/transform={rpath}{shift={(2,2)}}, spath/restore={rpath}] node[right] {transform}; 670 | \draw[orange] (3,0) [spath/insert={rpath}] node[right] {insert}; 671 | \draw[red] (3,-1) -- +(0,2) [spath/append={rpath}] node[above] {append}; 672 | \draw[spath/restore={rpath}] node[right] {restore}; 673 | \end{tikzpicture} 674 | 675 | \begin{tikzpicture} 676 | \path[spath/save=apath] (0,0) foreach \k in {1,...,4} { -- ++(1,0) +(0,0)}; 677 | \draw[ 678 | spath/shorten at end={apath}{7pt}, 679 | spath/shorten at start={apath}{9pt}, 680 | spath/translate={apath}{0pt}{1pt}, 681 | spath/restore=apath, 682 | ultra thick, red 683 | ]; 684 | \draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt]; 685 | \end{tikzpicture} 686 | 687 | \begin{tikzpicture} 688 | \path[spath/save=apath] (0,0) foreach \k in {1,...,4} { to[out=0,in=180] ++(1,0) +(0,0)}; 689 | \draw[ 690 | ultra thick, 691 | red, 692 | spath/.cd, 693 | shorten at end={apath}{7pt}, 694 | shorten at start={apath}{9pt}, 695 | translate={apath}{0pt}{1pt}, 696 | restore=apath, 697 | ]; 698 | \draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt]; 699 | \end{tikzpicture} 700 | 701 | \begin{tikzpicture} 702 | \draw[spath/save=npath] (0,0) foreach \k in {1,...,4} { -- ++(1,0) +(0,0)}; 703 | \draw[green] (0,0) -- +(0,-3pt) foreach \k in {1,...,4} { -- +(0,-3pt) ++(1,0)} -- +(0,-3pt); 704 | %\expandafter\show\csname tikz@intersect@path@name@npath\endcsname 705 | \tikzset{ 706 | spath/.cd, 707 | insert gaps after components={npath}{10pt}{1,3}, 708 | get components of={npath}\components, 709 | } 710 | %\show\components 711 | 712 | \tikzset{ 713 | path 1/.style={ 714 | red, 715 | }, 716 | } 717 | 718 | \foreach[count=\k] \cpt in \components { 719 | \path[ 720 | draw, 721 | path \k/.try, 722 | spath/.cd, 723 | translate=\cpt{0pt}{\k pt}, 724 | restore=\cpt, 725 | ] +(0,3pt) -- +(0,-3pt); 726 | \node[text=red] at (spath cs:{\cpt} .5) {\(\k\)}; 727 | } 728 | \end{tikzpicture} 729 | 730 | \begin{tikzpicture}[ 731 | use Hobby shortcut, 732 | ] 733 | 734 | \fill[red!50!white] (-.5,-.5) rectangle (8.5,1.5); 735 | \fill[pattern=bricks, pattern color=white] (-.5,-.5) rectangle (8.5,1.5); 736 | 737 | \path[spath/save=pathA] (0,0) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1); 738 | \path[spath/save=pathB] (0,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1); 739 | 740 | \tikzset{ 741 | spath/.cd, 742 | split at intersections={pathA}{pathB}, 743 | get components of={pathA}\pathAcomponents, 744 | get components of={pathB}\pathBcomponents, 745 | } 746 | 747 | \foreach[count=\k] \cpt in \pathAcomponents { 748 | \draw[spath/restore=\cpt,-|]; 749 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 750 | } 751 | 752 | \foreach[count=\k] \cpt in \pathBcomponents { 753 | \draw[spath/restore=\cpt,-|]; 754 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 755 | } 756 | 757 | \tikzset{ 758 | spath/.cd, 759 | insert gaps after components={pathA}{5pt}{1,3}, 760 | join components={pathA}{3,5}, 761 | get components of={pathA}\pathAcomponents, 762 | insert gaps after components={pathB}{5pt}{2,4}, 763 | join components={pathB}{2,4}, 764 | get components of={pathB}\pathBcomponents, 765 | } 766 | 767 | \foreach[count=\k] \cpt in \pathAcomponents { 768 | \draw[blue, line width=2pt,spath/restore=\cpt]; 769 | \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 770 | } 771 | 772 | \foreach[count=\k] \cpt in \pathBcomponents { 773 | \draw[green, line width=2pt,spath/restore=\cpt]; 774 | \node[fill=green!50, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 775 | } 776 | \end{tikzpicture} 777 | 778 | \begin{tikzpicture} 779 | \draw[spath/save=pathA] (0,0) -- (2,2); 780 | \draw[spath/save=pathB] (1,0) -- (0,1); 781 | 782 | \tikzset{ 783 | spath/.cd, 784 | split at intersections={pathA}{pathB}, 785 | get components of={pathA}\pathAcomponents, 786 | get components of={pathB}\pathBcomponents, 787 | } 788 | 789 | \foreach[count=\k] \cpt in \pathAcomponents { 790 | \draw[spath/restore=\cpt,-|]; 791 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 792 | } 793 | 794 | \foreach[count=\k] \cpt in \pathBcomponents { 795 | \draw[spath/restore=\cpt,-|]; 796 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 797 | } 798 | 799 | \tikzset{ 800 | spath/.cd, 801 | insert gaps after components={pathA}{5pt}{1}, 802 | get components of={pathA}\pathAcomponents, 803 | insert gaps after components={pathB}{5pt}{1}, 804 | get components of={pathB}\pathBcomponents, 805 | } 806 | 807 | \foreach[count=\k] \cpt in \pathAcomponents { 808 | \draw[blue, line width=2pt,spath/restore=\cpt]; 809 | % \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 810 | } 811 | 812 | \foreach[count=\k] \cpt in \pathBcomponents { 813 | \draw[green, line width=2pt,spath/restore=\cpt]; 814 | % \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 815 | } 816 | 817 | 818 | \end{tikzpicture} 819 | 820 | \begin{tikzpicture} 821 | \draw[ 822 | scale=2, 823 | spath/save=npath, 824 | ] (0,0) to[out=60,in=-90] (1,1) to[out=90,in=90] (0,1) to[out=-90,in=120] (1,0); 825 | 826 | \tikzset{ 827 | spath/.cd, 828 | split at self intersections=npath, 829 | get components of={npath}\npathcomponents, 830 | } 831 | 832 | \foreach[count=\k] \cpt in \npathcomponents { 833 | \draw[spath/restore=\cpt,-|]; 834 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 835 | } 836 | 837 | \tikzset{ 838 | spath/.cd, 839 | insert gaps after components={npath}{10pt}{2}, 840 | join components={npath}{2}, 841 | get components of={npath}\npathcomponents, 842 | } 843 | 844 | \foreach[count=\k] \cpt in \npathcomponents { 845 | \draw[blue, line width=2pt,spath/restore=\cpt]; 846 | % \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 847 | } 848 | 849 | \end{tikzpicture} 850 | 851 | \begin{tikzpicture} 852 | \draw[spath/save=line] (5,0) -- (2.5,0) -- ++(0,-.25) -- ++(-2.5,0) 853 | arc[radius=2.25cm,start angle=180,end angle=90] 854 | arc[radius=2cm,start angle=90, delta angle=-180] 855 | arc[radius=1.75cm,start angle=-90, delta angle=-180] 856 | arc[radius=1.5cm,start angle=90, delta angle=-180] 857 | arc[radius=1.25cm,start angle=-90, delta angle=-180] 858 | arc[radius=1cm,start angle=90, delta angle=-180] 859 | arc[radius=.75cm,start angle=-90, delta angle=-180] 860 | arc[radius=.5cm,start angle=90, delta angle=-180] 861 | ; 862 | 863 | \tikzset{ 864 | spath/.cd, 865 | split at self intersections=line, 866 | get components of={line}\pathcomponents, 867 | } 868 | 869 | \foreach[count=\k] \cpt in \pathcomponents { 870 | \draw[spath/restore=\cpt,-|]; 871 | \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 872 | } 873 | 874 | 875 | \tikzset{ 876 | spath/.cd, 877 | insert gaps after components={line}{10pt}{1,3,5,7,10,11,14}, 878 | % join components={line}{2,4,6,8,9,12,13}, 879 | get components of={line}\pathcomponents, 880 | } 881 | 882 | \foreach[count=\k] \cpt in \pathcomponents { 883 | \draw[blue, line width=2pt,spath/restore=\cpt]; 884 | % \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; 885 | } 886 | 887 | 888 | \end{tikzpicture} 889 | 890 | 891 | \end{document} 892 | -------------------------------------------------------------------------------- /examples/spath_interface.tex: -------------------------------------------------------------------------------- 1 | %\RequirePackage{shellesc} 2 | %\immediate\write18{cd ..; tex spath3.dtx} 3 | \documentclass{article} 4 | %\url{https://tex.stackexchange.com/q/484027/86} 5 | \usepackage{tikz} 6 | \usetikzlibrary{hobby, calc, spath3} 7 | 8 | \begin{document} 9 | 10 | \begin{tikzpicture}[use Hobby shortcut] 11 | \path[spath/save = A] 12 | (3.18, 1.05).. 13 | (2.7,.58).. 14 | (2.45,-.95).. 15 | (1.81,-1.35) 16 | ; 17 | \path[spath/save = B] 18 | (3.18, 1.05).. 19 | (1.73,1.01).. 20 | (0,.57).. 21 | (-1.07,0).. 22 | (-1.43, -.26).. 23 | (-1.76,-.61).. 24 | (-1.81,-.89).. 25 | (-1.56,-.91).. 26 | (-.95, -.78).. 27 | (0,-.66).. 28 | (.79,-.7).. 29 | (1.23,-.88).. 30 | (1.81,-1.35) 31 | ; 32 | 33 | \filldraw[ 34 | fill=blue, 35 | draw=black, 36 | ultra thick, 37 | spath/restore=A 38 | ] 39 | [spath/append reverse=B] 40 | -- cycle; 41 | \end{tikzpicture} 42 | 43 | \begin{tikzpicture}[use Hobby shortcut] 44 | 45 | \path[overlay,spath/save = A] 46 | (3.18, 1.05).. 47 | (2.7,.58).. 48 | (2.45,-.95).. 49 | (1.81,-1.35) 50 | ; 51 | 52 | 53 | \filldraw[fill=blue, draw=black, ultra thick] 54 | (3.18, 1.05).. 55 | (1.73,1.01).. 56 | (0,.57).. 57 | (-1.07,0).. 58 | (-1.43, -.26).. 59 | (-1.76,-.61).. 60 | (-1.81,-.89).. 61 | (-1.56,-.91).. 62 | (-.95, -.78).. 63 | (0,-.66).. 64 | (.79,-.7).. 65 | (1.23,-.88).. 66 | ([Hobby finish]1.81,-1.35) % needed to trigger hobby path generation before adding the new path 67 | [spath/append reverse=A] -- cycle 68 | ; 69 | \end{tikzpicture} 70 | \end{document} 71 | -------------------------------------------------------------------------------- /examples/testpaths.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{tikz} 4 | \usetikzlibrary{spath3} 5 | 6 | \begin{document} 7 | 8 | \section{Original Paths} 9 | 10 | \begin{tikzpicture} 11 | \draw[spath/show current path] (0,0) -- (2,1); 12 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0); 13 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0); 14 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle; 15 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle; 16 | \end{tikzpicture} 17 | 18 | \section{Reversed Paths} 19 | 20 | \begin{tikzpicture} 21 | \draw[spath/show current path] (2,1) -- (0,0); 22 | \draw[spath/show current path] (4,1) to[out=150,in=30] +(-2,0) -- (0,0); 23 | \draw[spath/show current path] (4,1) to[out=150,in=30] +(-2,0) +(0,0) -- (0,0); 24 | \draw[spath/show current path] (4,1) to[out=150,in=30] +(-2,0) -- (0,0) -- cycle; 25 | \draw[spath/show current path] (4,1) to[out=150,in=30] +(-2,0) -- cycle (2,1) -- (0,0); 26 | \end{tikzpicture} 27 | 28 | \section{Translated Paths} 29 | 30 | \begin{tikzpicture} 31 | \begin{scope}[shift={(2,3)}] 32 | \draw[spath/show current path] (0,0) -- (2,1); 33 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0); 34 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0); 35 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle; 36 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle; 37 | \end{scope} 38 | 39 | \end{tikzpicture} 40 | 41 | \section{Scaled Paths} 42 | 43 | \begin{tikzpicture} 44 | \begin{scope}[xscale=5, yscale=2] 45 | \draw[spath/show current path] (0,0) -- (2,1); 46 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0); 47 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0); 48 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle; 49 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle; 50 | \end{scope} 51 | 52 | \end{tikzpicture} 53 | 54 | \section{Transformed Paths} 55 | 56 | \begin{tikzpicture} 57 | \begin{scope}[xscale=.5, yscale=2, rotate=60, shift={(-2,-3)}] 58 | \draw[spath/show current path] (0,0) -- (2,1); 59 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0); 60 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0); 61 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle; 62 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle; 63 | \path[spath/show current path] (0,0) (1,0) (0,1); 64 | \end{scope} 65 | \begin{scope}[xscale=.5, yscale=2, rotate=60] 66 | \path[spath/show current path] (0,0) (1pt,0) (0,1pt); 67 | \end{scope} 68 | \end{tikzpicture} 69 | 70 | \section{welded Paths} 71 | 72 | \begin{tikzpicture} 73 | \draw[spath/show current path] (0,0) to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 74 | \draw[spath/show current path] (0,0) -- (2,1) to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 75 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 76 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 77 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 78 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle to[out=-30,in=-90] ++(1,2) -- ++(-1,-3); 79 | \end{tikzpicture} 80 | 81 | \section{Appended Paths, No Move} 82 | 83 | \begin{tikzpicture} 84 | \draw[spath/show current path] (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 85 | \draw[spath/show current path] (0,0) -- (2,1) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 86 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 87 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 88 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 89 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 90 | \end{tikzpicture} 91 | 92 | \section{Appended Paths} 93 | 94 | \begin{tikzpicture} 95 | \draw[spath/show current path] (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 96 | \draw[spath/show current path] (0,0) -- (2,1) (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 97 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 98 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 99 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 100 | \draw[spath/show current path] (0,0) -- (2,1) +(0,0) to[out=30, in=150] +(2,0) -- cycle (0,0) .. controls (0,1) and (0,-1) .. (2,-1) -- (1,2); 101 | \end{tikzpicture} 102 | 103 | \section{Intersection Components} 104 | 105 | \begin{tikzpicture} 106 | \draw[spath/show current path] (0,0) -- (2,1); 107 | \draw[spath/show current path] (.75,-2) rectangle ++(-1,2); 108 | \draw[spath/show current path] (-1,.5) rectangle ++(2,1); 109 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0); 110 | \draw[spath/show current path] (0,0) -- (2,1) to[out=30, in=150] +(2,0) -- cycle; 111 | \draw[spath/show current path, red] (.5,-1) to[out=0,in=180] ++(.5,3) to[out=0,in=180] ++(.5,-3) to[out=0,in=180] ++(.5,3) to[out=0,in=180] ++(.5,-3) to[out=0,in=180] ++(.5,3) to[out=0,in=180] ++(.5,-3) 112 | ; 113 | 114 | \draw[ultra thick, blue] 115 | (0.0pt,0.0pt) -- 116 | (22.0895731082pt,11.0447846132pt) 117 | (22.0895731082pt,11.0447846132pt) -- 118 | (36.4826786939pt,18.2413361414pt) 119 | (36.4826786939pt,18.2413361414pt) -- 120 | (47.652657326pt,23.826324476pt) 121 | (47.652657326pt,23.826324476pt) -- 122 | (56.90549pt,28.45274pt) 123 | ; 124 | 125 | \fill 126 | (22.0895731082pt,11.0447846132pt) circle[radius=2pt] 127 | (36.4826786939pt,18.2413361414pt) circle[radius=2pt] 128 | (47.652657326pt,23.826324476pt) circle[radius=2pt] 129 | ; 130 | 131 | 132 | \draw[ultra thick, green] 133 | (21.33955pt,-26.5355990419pt) -- 134 | (21.33955pt,0.0pt) -- 135 | (-7.11319pt,0.0pt) -- 136 | (-7.11319pt,-56.90549pt) -- 137 | (21.33955pt,-56.90549pt) -- 138 | (21.33955pt,-26.5355990419pt) 139 | ; 140 | 141 | \draw[ultra thick, green] 142 | (16.6994821608pt,42.67911pt) -- 143 | (28.45274pt,42.67911pt) -- 144 | (28.45274pt,14.22636pt) -- 145 | (21.3674386852pt,14.22636pt) 146 | (21.3674386852pt,14.22636pt) -- 147 | (-28.45274pt,14.22636pt) -- 148 | (-28.45274pt,42.67911pt) -- 149 | (16.6994821608pt,42.67911pt) 150 | ; 151 | 152 | \fill 153 | (21.33955pt,-26.5355990419pt) circle[radius=2pt] 154 | (21.3674386852pt,14.22636pt) circle[radius=2pt] 155 | (16.6994821608pt,42.67911pt) circle[radius=2pt] 156 | ; 157 | 158 | \draw[ultra thick, magenta] 159 | (0.0pt,0.0pt) -- 160 | (22.0895731082pt,11.0447846132pt) 161 | (22.0895731082pt,11.0447846132pt) -- 162 | (36.4826786939pt,18.2413361414pt) 163 | (36.4826786939pt,18.2413361414pt) -- 164 | (47.652657326pt,23.826324476pt) 165 | (47.652657326pt,23.826324476pt) -- 166 | (56.90549pt,28.45274pt) .. controls 167 | (60.61213895060001pt,30.5927695877pt) and 168 | (64.29090142112955pt,32.32005166882031pt) .. 169 | (67.95253434241103pt,33.63458624336091pt) 170 | (67.95253434241103pt,33.63458624336091pt) .. controls 171 | (69.99209064838535pt,34.36679161144769pt) and 172 | (72.02633238933044pt,34.97093911691348pt) .. 173 | (74.05711852959721pt,35.4470287597583pt) 174 | (74.05711852959721pt,35.4470287597583pt) .. controls 175 | (81.60711373040281pt,37.21702041341389pt) and 176 | (89.10934626959721pt,37.2170204134139pt) .. 177 | (96.6593414704028pt,35.4470287597583pt) 178 | (96.6593414704028pt,35.4470287597583pt) .. controls 179 | (102.3360153782694pt,34.1162112995861pt) and 180 | (108.039690486pt,31.784781713pt) .. 181 | (113.81097pt,28.45274pt) 182 | ; 183 | 184 | \fill 185 | (22.0895731082pt,11.0447846132pt) circle[radius=3pt] 186 | (36.4826786939pt,18.2413361414pt) circle[radius=3pt] 187 | (47.652657326pt,23.826324476pt) circle[radius=3pt] 188 | (67.95253434241103pt,33.63458624336091pt) circle[radius=3pt] 189 | (74.05711852959721pt,35.4470287597583pt) circle[radius=3pt] 190 | (96.6593414704028pt,35.4470287597583pt) circle[radius=3pt] 191 | (113.81097pt,28.45274pt) circle[radius=3pt] 192 | ; 193 | 194 | \draw[ultra thick, orange, spath/show current path] 195 | (22.0895731082pt,11.0447846132pt) -- 196 | (36.4826786939pt,18.2413361414pt) 197 | (36.4826786939pt,18.2413361414pt) -- 198 | (47.652657326pt,23.826324476pt) 199 | (47.652657326pt,23.826324476pt) -- 200 | (56.90549pt,28.45274pt) .. controls 201 | (60.61213895060001pt,30.5927695877pt) and 202 | (64.29090142112955pt,32.32005166882031pt) .. 203 | (67.95253434241103pt,33.63458624336091pt) 204 | (67.95253434241103pt,33.63458624336091pt) .. controls 205 | (69.99209064838535pt,34.36679161144769pt) and 206 | (72.02633238933044pt,34.97093911691348pt) .. 207 | (74.05711852959721pt,35.4470287597583pt) 208 | (74.05711852959721pt,35.4470287597583pt) .. controls 209 | (81.60711373040281pt,37.21702041341389pt) and 210 | (89.10934626959721pt,37.2170204134139pt) .. 211 | (96.6593414704028pt,35.4470287597583pt) 212 | (96.6593414704028pt,35.4470287597583pt) .. controls 213 | (102.3360153782694pt,34.1162112995861pt) and 214 | (108.039690486pt,31.784781713pt) .. 215 | (113.81097pt,28.45274pt) -- 216 | (94.61105936100003pt,23.652762762pt) 217 | (94.61105936100003pt,23.652762762pt) -- 218 | (77.10579406530003pt,19.2764468226pt) 219 | (77.10579406530003pt,19.2764468226pt) -- 220 | (64.43521877520001pt,16.1088032784pt) 221 | (64.43521877520001pt,16.1088032784pt) -- 222 | (50.15308014989997pt,12.53826893579999pt) 223 | (50.15308014989997pt,12.53826893579999pt) -- 224 | (34.31514556469996pt,8.57878563739999pt) 225 | (34.31514556469996pt,8.57878563739999pt) -- 226 | (23.2572717195pt,5.814317419pt) 227 | (23.2572717195pt,5.814317419pt) -- 228 | (0.0pt,0.0pt) -- (22.0895731082pt,11.0447846132pt) 229 | ; 230 | 231 | \fill 232 | (36.4826786939pt,18.2413361414pt) circle[radius=3pt] 233 | (47.652657326pt,23.826324476pt) circle[radius=3pt] 234 | (67.95253434241103pt,33.63458624336091pt) circle[radius=3pt] 235 | (74.05711852959721pt,35.4470287597583pt) circle[radius=3pt] 236 | (96.6593414704028pt,35.4470287597583pt) circle[radius=3pt] 237 | (94.61105936100003pt,23.652762762pt) circle[radius=3pt] 238 | (77.10579406530003pt,19.2764468226pt) circle[radius=3pt] 239 | (64.43521877520001pt,16.1088032784pt) circle[radius=3pt] 240 | (50.15308014989997pt,12.53826893579999pt) circle[radius=3pt] 241 | (34.31514556469996pt,8.57878563739999pt) circle[radius=3pt] 242 | (23.2572717195pt,5.814317419pt) circle[radius=3pt] 243 | (22.0895731082pt,11.0447846132pt) circle[radius=3pt] 244 | ; 245 | 246 | 247 | \end{tikzpicture} 248 | 249 | \begin{tikzpicture} 250 | 251 | \fill 252 | (21.33955pt, -26.5355990419pt) circle[radius=2pt] 253 | (21.33955pt, -56.90549pt) circle[radius=2pt] 254 | ; 255 | 256 | \draw[ultra thick, red] 257 | (21.33955pt, -26.5355990419pt) -- 258 | (21.33955pt, 0.0pt) -- 259 | (-7.11319pt, 0.0pt) -- 260 | (-7.11319pt, -56.90549pt) -- 261 | (21.33955pt, -56.90549pt) -- 262 | (21.33955pt, -26.5355990419pt) 263 | ; 264 | 265 | 266 | \draw 267 | (21.33955pt, -56.90549pt) -- 268 | (21.33955pt, -26.5355990419pt) 269 | (21.33955pt, -26.5355990419pt) -- 270 | (21.33955pt, 0.0pt) -- 271 | (-7.11319pt, 0.0pt) -- 272 | (-7.11319pt, -56.90549pt) -- 273 | (21.33955pt, -56.90549pt) 274 | ; 275 | \end{tikzpicture} 276 | 277 | \end{document} 278 | -------------------------------------------------------------------------------- /examples/trefoil_moves.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \thispagestyle{empty} 3 | \usepackage[scale=.9,landscape]{geometry} 4 | \usepackage{subcaption} 5 | \usepackage{tikz} 6 | \usetikzlibrary{ 7 | knots, 8 | hobby, 9 | external, 10 | decorations.pathreplacing, 11 | shapes.geometric 12 | } 13 | 14 | \tikzset{ 15 | external/figure name=knot, 16 | external/prefix=knotdiagrams/trefoil-, 17 | show curve controls/.style={ 18 | postaction=decorate, 19 | decoration={show path construction, 20 | curveto code={ 21 | \draw [blue, dashed] 22 | (\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta) 23 | node [at end, draw, solid, red, inner sep=2pt]{}; 24 | \draw [blue, dashed] 25 | (\tikzinputsegmentsupportb) -- (\tikzinputsegmentlast) 26 | node [at start, draw, solid, red, inner sep=2pt]{} 27 | node [at end, fill, blue, ellipse, inner sep=2pt]{} 28 | ; 29 | } 30 | } 31 | }, 32 | show curve endpoints/.style={ 33 | postaction=decorate, 34 | decoration={show path construction, 35 | curveto code={ 36 | \node [fill, blue, ellipse, inner sep=2pt] at (\tikzinputsegmentlast) {} 37 | ; 38 | } 39 | } 40 | } 41 | } 42 | 43 | \tikzexternalize 44 | 45 | \let\origtikzsetnextfilename\tikzsetnextfilename 46 | \def\tikzsetnextfilename#1{% 47 | \origtikzsetnextfilename{#1}% 48 | \mysetlabel{#1}% 49 | } 50 | 51 | \newcommand{\mysetlabel}[1]{% 52 | \gdef\mynextlabel{#1}} 53 | 54 | \newcommand{\autolabel}{% 55 | \label{fig:\mynextlabel} 56 | \global\let\mynextlabel\relax 57 | } 58 | 59 | 60 | \tikzset{ 61 | use Hobby shortcut, 62 | knot diagram/every strand/.append style={ 63 | ultra thick,red 64 | }, 65 | every picture/.style={ 66 | execute at end picture={% 67 | \path ([shift={(-5pt,-5pt)}]current bounding box.south west) ([shift={(5pt,5pt)}]current bounding box.north east); 68 | } 69 | } 70 | } 71 | 72 | \begin{document} 73 | %\tikzset{external/force remake=true} 74 | 75 | \begin{figure} 76 | %% Trefoil 77 | \subcaptionbox{Trefoil}[.25\linewidth][c]{% 78 | \tikzsetnextfilename{trefoil} 79 | %\tikzset{external/export next=false} 80 | \begin{tikzpicture} 81 | \begin{knot}[ 82 | consider self intersections=true, 83 | % draft mode=crossings, 84 | flip crossing=2, 85 | only when rendering/.style={ 86 | % show curve endpoints 87 | } 88 | ] 89 | \strand ([closed,blank=soft]90:2) .. ([blank=soft]-.75,1) .. (210:.5) .. (330:2) .. (90:.5) .. (210:2) .. (330:.5) .. (.75,1); 90 | \strand[blue,use previous Hobby path={disjoint,invert soft blanks}]; 91 | \end{knot} 92 | \end{tikzpicture} 93 | \autolabel 94 | }% 95 | %% Trefoil first twist 96 | \subcaptionbox{Trefoil: First Twist}[.25\linewidth][c]{% 97 | \tikzsetnextfilename{twist} 98 | %\tikzset{external/export next=false} 99 | \centering 100 | \begin{tikzpicture} 101 | \begin{knot}[ 102 | consider self intersections=true, 103 | end tolerance=3pt, 104 | % draft mode=crossings, 105 | flip crossing/.list={1,3,4} 106 | ] 107 | \strand ([closed]1,4) .. (1,3.5) .. ([blank=soft]210:.75) .. (330:2) .. (90:.5) .. (210:2) .. (330:.75) .. (-1,3.5) .. (-1,4); 108 | \strand[blue,use previous Hobby path={invert soft blanks,disjoint}]; 109 | \end{knot} 110 | \end{tikzpicture} 111 | \autolabel 112 | }% 113 | %% Trefoil first move 114 | \subcaptionbox{Trefoil: Move Over}[.25\linewidth][c]{% 115 | \tikzsetnextfilename{first-over} 116 | %\tikzset{external/export next=false} 117 | \centering 118 | \begin{tikzpicture} 119 | \begin{knot}[ 120 | consider self intersections=true, 121 | end tolerance=3pt, 122 | % draft mode=crossings, 123 | flip crossing/.list={1,2,4} 124 | ] 125 | \strand ([closed]1,2) .. ([blank=soft]1,0) .. ([blank=soft]210:.75) .. (330:2) .. (90:.75) .. (210:2) .. (330:.75) .. (-1,2); 126 | \strand[blue,use previous Hobby path={invert soft blanks,disjoint}]; 127 | \end{knot} 128 | \end{tikzpicture} 129 | \autolabel 130 | }% 131 | %% Trefoil slide round 132 | \subcaptionbox{Trefoil: Slide Round}[.25\linewidth][c]{% 133 | \tikzsetnextfilename{slide-round} 134 | %\tikzset{external/export next=false} 135 | \centering 136 | \begin{tikzpicture} 137 | \begin{knot}[ 138 | consider self intersections=true, 139 | end tolerance=3pt, 140 | % draft mode=crossings, 141 | flip crossing/.list={1,2,4}, 142 | only when rendering/.style={ 143 | % show curve endpoints 144 | } 145 | ] 146 | \strand ([closed]2,1) .. (2,-2) .. ([blank=soft]1,-1) .. ([blank=soft]-.5,-1) .. (330:2) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 147 | \strand[blue,use previous Hobby path={invert soft blanks,disjoint}]; 148 | \end{knot} 149 | \end{tikzpicture} 150 | \autolabel 151 | } 152 | \end{figure} 153 | 154 | \begin{figure} 155 | %% Trefoil second move 156 | \subcaptionbox{Trefoil: Second Move}[.25\linewidth][c]{% 157 | \tikzsetnextfilename{second-move} 158 | %\tikzset{external/export next=false} 159 | \centering 160 | \begin{tikzpicture} 161 | \begin{knot}[ 162 | consider self intersections=true, 163 | end tolerance=3pt, 164 | % draft mode=crossings, 165 | flip crossing/.list={2}, 166 | only when rendering/.style={ 167 | % show curve endpoints 168 | } 169 | ] 170 | \strand ([closed]2,1) .. (2,-2) .. (-.5,-1.5) .. ([blank=soft]-.5,0) .. ([blank=soft]-.75,-.25) .. ([blank=soft]0,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 171 | \strand[blue,use previous Hobby path={invert soft blanks,disjoint}]; 172 | \end{knot} 173 | \end{tikzpicture} 174 | \autolabel 175 | }% 176 | %% Trefoil untwist 177 | \subcaptionbox{Trefoil: Untwist}[.25\linewidth][c]{% 178 | \tikzsetnextfilename{untwist} 179 | %\tikzset{external/export next=false} 180 | \centering 181 | \begin{tikzpicture} 182 | \begin{knot}[ 183 | consider self intersections=true, 184 | end tolerance=3pt, 185 | % draft mode=crossings, 186 | flip crossing/.list={2}, 187 | only when rendering/.style={ 188 | % show curve endpoints 189 | } 190 | ] 191 | \strand ([closed]2,1) .. (2,-2) .. (-.5,-1.5) .. (0,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 192 | \end{knot} 193 | \end{tikzpicture} 194 | \autolabel 195 | }% 196 | %% Trefoil slide round 197 | \subcaptionbox{Trefoil: Slide Round Again}[.25\linewidth][c]{% 198 | \tikzsetnextfilename{slide-again} 199 | %\tikzset{external/export next=false} 200 | \centering 201 | \begin{tikzpicture} 202 | \begin{knot}[ 203 | consider self intersections=true, 204 | end tolerance=3pt, 205 | % draft mode=crossings, 206 | flip crossing/.list={2}, 207 | only when rendering/.style={ 208 | % show curve endpoints 209 | } 210 | ] 211 | \strand ([closed]2.5,.5) .. (2,-2) .. (-.5,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (-1,-2) .. (330:.75); 212 | \end{knot} 213 | \end{tikzpicture} 214 | \autolabel 215 | }% 216 | %% Trefoil neaten 217 | \subcaptionbox{Trefoil: Neaten}[.25\linewidth][c]{% 218 | \tikzsetnextfilename{neaten} 219 | %\tikzset{external/export next=false} 220 | \centering 221 | \begin{tikzpicture} 222 | \begin{knot}[ 223 | consider self intersections=true, 224 | end tolerance=3pt, 225 | % draft mode=crossings, 226 | flip crossing/.list={2}, 227 | only when rendering/.style={ 228 | % show curve endpoints 229 | } 230 | ] 231 | \strand ([closed]0,2) .. (2,0) .. (-1,-1) .. (1,-3) .. (3,-1) .. (1,1) .. (0,-2) .. (-2,0); 232 | \end{knot} 233 | \end{tikzpicture} 234 | \autolabel 235 | } 236 | \end{figure} 237 | 238 | \end{document} 239 | -------------------------------------------------------------------------------- /examples/trefoil_moves_new.tex: -------------------------------------------------------------------------------- 1 | \RequirePackage{shellesc} 2 | %\immediate\write18{cd ..; tex spath3_code.dtx} 3 | \documentclass{article} 4 | \thispagestyle{empty} 5 | \usepackage[scale=.9,landscape]{geometry} 6 | \usepackage{subcaption} 7 | \usepackage{tikz} 8 | \usetikzlibrary{ 9 | knots, 10 | hobby, 11 | external, 12 | decorations.pathreplacing, 13 | shapes.geometric 14 | } 15 | 16 | \tikzset{ 17 | external/figure name=knot, 18 | external/prefix=knotdiagrams/new-trefoil-, 19 | external/system call={pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource" && pdftoppm -png -singlefile "\image.pdf" "\image"}, 20 | } 21 | 22 | \tikzexternalize 23 | 24 | \let\origtikzsetnextfilename\tikzsetnextfilename 25 | \def\tikzsetnextfilename#1{% 26 | \origtikzsetnextfilename{#1}% 27 | \mysetlabel{#1}% 28 | } 29 | 30 | \newcommand{\mysetlabel}[1]{% 31 | \gdef\mynextlabel{#1}} 32 | 33 | \newcommand{\autolabel}{% 34 | \label{fig:\mynextlabel} 35 | \global\let\mynextlabel\relax 36 | } 37 | 38 | 39 | \tikzset{ 40 | use Hobby shortcut, 41 | trefoil/.style={ 42 | draw, 43 | ultra thick, 44 | red 45 | }, 46 | every picture/.style={ 47 | execute at end picture={% 48 | \path ([shift={(-5pt,-5pt)}]current bounding box.south west) ([shift={(5pt,5pt)}]current bounding box.north east); 49 | } 50 | } 51 | } 52 | 53 | \begin{document} 54 | %\tikzset{external/force remake=true} 55 | 56 | \begin{figure} 57 | %% Trefoil 58 | \subcaptionbox{Trefoil}[.25\linewidth][c]{% 59 | \tikzsetnextfilename{trefoil} 60 | %\tikzset{external/export next=false} 61 | \begin{tikzpicture}[ 62 | every trefoil component/.style={trefoil}, 63 | trefoil component 3/.style={blue} 64 | ] 65 | 66 | \path[spath/save=trefoil] ([closed]90:2) .. (-.75,1) .. (210:.5) .. (330:2) .. (90:.5) .. (210:2) .. (330:.5) .. (.75,1); 67 | \tikzset{ 68 | spath/knot={trefoil}{5pt}{2,4,6} 69 | } 70 | \end{tikzpicture} 71 | \autolabel 72 | }% 73 | %% Trefoil first twist 74 | \subcaptionbox{Trefoil: First Twist}[.25\linewidth][c]{% 75 | \tikzsetnextfilename{twist} 76 | %\tikzset{external/export next=false} 77 | \centering 78 | \begin{tikzpicture}[ 79 | every first twist component/.style={trefoil}, 80 | first twist component 3/.style={blue}, 81 | first twist component 4/.style={blue}, 82 | ] 83 | \path[spath/save=first twist] ([closed]1,4) .. (1,3.5) .. (210:.75) .. (330:2) .. (90:.5) .. (210:2) .. (330:.75) .. (-1,3.5) .. (-1,4); 84 | \tikzset{ 85 | spath/knot={first twist}{5pt}{3,5,7,8}, 86 | } 87 | \end{tikzpicture} 88 | \autolabel 89 | }% 90 | %% Trefoil first move 91 | \subcaptionbox{Trefoil: Move Over}[.25\linewidth][c]{% 92 | \tikzsetnextfilename{first-over} 93 | %\tikzset{external/export next=false} 94 | \centering 95 | \begin{tikzpicture}[ 96 | every first-over component/.style={trefoil}, 97 | first-over component 4/.style={blue} 98 | ] 99 | \path[spath/save=first-over] ([closed]1,2) .. (1,0) .. (210:.75) .. (330:2) .. (90:.75) .. (210:2) .. (330:.75) .. (-1,2); 100 | \tikzset{ 101 | spath/knot={first-over}{5pt}{3,4,7,8}, 102 | } 103 | \end{tikzpicture} 104 | \autolabel 105 | }% 106 | %% Trefoil slide round 107 | \subcaptionbox{Trefoil: Slide Round}[.25\linewidth][c]{% 108 | \tikzsetnextfilename{slide-round} 109 | %\tikzset{external/export next=false} 110 | \centering 111 | \begin{tikzpicture}[ 112 | every slide-round component/.style={trefoil}, 113 | slide-round component 4/.style={blue} 114 | ] 115 | \path[spath/save=slide-round] ([closed]2,1) .. (2,-2) .. (1,-1) .. (-.5,-1) .. (330:2) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 116 | \tikzset{ 117 | spath/knot={slide-round}{5pt}{3,4,7,8}, 118 | } 119 | \end{tikzpicture} 120 | \autolabel 121 | } 122 | \end{figure} 123 | 124 | \begin{figure} 125 | %% Trefoil second move 126 | \subcaptionbox{Trefoil: Second Move}[.25\linewidth][c]{% 127 | \tikzsetnextfilename{second-move} 128 | %\tikzset{external/export next=false} 129 | \centering 130 | \begin{tikzpicture}[ 131 | every second-move component/.style={trefoil}, 132 | second-move component 1/.style={blue}, 133 | second-move component 4/.style={blue} 134 | ] 135 | \path[spath/save=second-move] ([closed]2,1) .. (2,-2) .. (-.5,-1.5) .. (-.5,0) .. (-.75,-.25) .. (0,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 136 | \tikzset{ 137 | spath/knot={second-move}{5pt}{3,4,6,8}, 138 | } 139 | \end{tikzpicture} 140 | \autolabel 141 | }% 142 | %% Trefoil untwist 143 | \subcaptionbox{Trefoil: Untwist}[.25\linewidth][c]{% 144 | \tikzsetnextfilename{untwist} 145 | %\tikzset{external/export next=false} 146 | \centering 147 | \begin{tikzpicture}[ 148 | every untwist component/.style={trefoil}, 149 | untwist component 3/.style={blue} 150 | ] 151 | \path[spath/save=untwist] ([closed]2,1) .. (2,-2) .. (-.5,-1.5) .. (0,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (330:.75) .. (-1,2); 152 | \tikzset{ 153 | spath/knot={untwist}{5pt}{2,4,6}, 154 | } 155 | \end{tikzpicture} 156 | \autolabel 157 | }% 158 | %% Trefoil slide round 159 | \subcaptionbox{Trefoil: Slide Round Again}[.25\linewidth][c]{% 160 | \tikzsetnextfilename{slide-again} 161 | %\tikzset{external/export next=false} 162 | \centering 163 | \begin{tikzpicture}[ 164 | every slide-again component/.style={trefoil}, 165 | slide-again component 3/.style={blue} 166 | ] 167 | \path[spath/save=slide-again] ([closed]2.5,.5) .. (2,-2) .. (-.5,-1) .. (1.5,-1) .. (0.25,.75) .. (210:2) .. (-1,-2) .. (330:.75); 168 | \tikzset{ 169 | spath/knot={slide-again}{5pt}{2,4,6}, 170 | } 171 | \end{tikzpicture} 172 | \autolabel 173 | }% 174 | %% Trefoil neaten 175 | \subcaptionbox{Trefoil: Neaten}[.25\linewidth][c]{% 176 | \tikzsetnextfilename{neaten} 177 | %\tikzset{external/export next=false} 178 | \centering 179 | \begin{tikzpicture}[ 180 | every neaten component/.style={trefoil} 181 | ] 182 | \path[spath/save=neaten] ([closed]0,2) .. (2,0) .. (-1,-1) .. (1,-3) .. (3,-1) .. (1,1) .. (0,-2) .. (-2,0); 183 | \tikzset{ 184 | spath/knot={neaten}{5pt}{2,4,6}, 185 | } 186 | \end{tikzpicture} 187 | \autolabel 188 | } 189 | \end{figure} 190 | 191 | \end{document} 192 | -------------------------------------------------------------------------------- /examples/twistedpair.tex: -------------------------------------------------------------------------------- 1 | \documentclass[tikz,border=3mm]{standalone} 2 | %\url{https://tex.stackexchange.com/q/532840/86} 3 | \usetikzlibrary{knots} 4 | 5 | \begin{document} 6 | \begin{tikzpicture}[ 7 | basic strand/.style={ 8 | double=., 9 | draw=black, 10 | looseness=1.2, 11 | double distance=6pt, 12 | line cap=round 13 | }, 14 | crossing strand/.style={ 15 | line width=6.8pt, 16 | only when rendering/.style={% 17 | draw=\pgfinnerstrokecolor,% 18 | line width=6pt, 19 | double=none, 20 | } 21 | } 22 | ] 23 | \begin{knot}[%draft mode = crossings, % uncomment to see where the crossings are 24 | clip width = 1, 25 | flip crossing/.list={1,3,5,7,9}, 26 | background color=black, 27 | only when rendering/.style={% 28 | basic strand 29 | },% 30 | every intersection/.style={ 31 | crossing strand 32 | }, 33 | ] 34 | \path foreach \X in {0,4.5} {foreach \Y in {0.2,-0.2} 35 | {(1.6*\X,\Y) node[draw,fill=orange,inner ysep=1.5pt,inner xsep=8pt,rounded 36 | corners=1.5pt]{}}}; 37 | \strand[white] 38 | plot[domain=0:4.5,samples=251] (1.6*\x,{0.2*cos(\x*360)}); 39 | \strand[green!60!black] 40 | plot[domain=0:4.5,samples=251] (1.6*\x,{-0.2*cos(\x*360)}); 41 | \end{knot} 42 | \end{tikzpicture} 43 | \end{document} 44 | -------------------------------------------------------------------------------- /examples/twistedpair_celtic.tex: -------------------------------------------------------------------------------- 1 | \documentclass[tikz,border=3mm]{standalone} 2 | %\url{https://tex.stackexchange.com/q/532840/86} 3 | \usetikzlibrary{knots,celtic} 4 | 5 | \begin{document} 6 | \begin{tikzpicture}[ 7 | basic strand/.style={ 8 | double=., 9 | draw=black, 10 | looseness=1.2, 11 | double distance=6pt, 12 | line cap=round 13 | }, 14 | crossing strand/.style={ 15 | line width=6.8pt, 16 | only when rendering/.style={% 17 | draw=\pgfinnerstrokecolor,% 18 | line width=6pt, 19 | double=none, 20 | } 21 | } 22 | ] 23 | \begin{knot}[%draft mode = crossings, % uncomment to see where the crossings are 24 | clip width = 1, 25 | flip crossing/.list={1,3,5,7,9}, 26 | background color=black, 27 | only when rendering/.style={% 28 | basic strand 29 | },% 30 | every intersection/.style={ 31 | crossing strand 32 | }, 33 | ] 34 | \path foreach \X in {0,4.5} {foreach \Y in {0.2,-0.2} 35 | {(1.6*\X,\Y) node[draw,fill=orange,inner ysep=1.5pt,inner xsep=8pt,rounded 36 | corners=1.5pt]{}}}; 37 | \strand[white] 38 | plot[domain=0:4.5,samples=251] (1.6*\x,{0.2*cos(\x*360)}); 39 | \strand[green!60!black] 40 | plot[domain=0:4.5,samples=251] (1.6*\x,{-0.2*cos(\x*360)}); 41 | \end{knot} 42 | \end{tikzpicture} 43 | 44 | \begin{tikzpicture}[ 45 | celtic path/.style={ 46 | draw, 47 | double, 48 | black, 49 | double distance=6pt 50 | }, 51 | celtic path 1/.style={ 52 | double=white 53 | }, 54 | celtic path 1/.style={ 55 | double=green 56 | } 57 | ] 58 | \CelticDrawPath{ 59 | size={2,10} 60 | } 61 | \end{tikzpicture} 62 | \end{document} 63 | -------------------------------------------------------------------------------- /examples/welding.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{tikz} 4 | \usetikzlibrary{spath3} 5 | 6 | \makeatletter 7 | \tikzset{ 8 | show path/.code={ 9 | \pgfsyssoftpath@getcurrentpath\@temp 10 | \show\@temp 11 | }, 12 | show path at end/.code={ 13 | \tikz@addmode{ 14 | \pgfsyssoftpath@getcurrentpath\@temp 15 | \show\@temp 16 | } 17 | } 18 | } 19 | \makeatother 20 | 21 | \begin{document} 22 | 23 | \begin{tikzpicture} 24 | \path[save spath=A] (0,0) to[out=0,in=180] (3,2); 25 | \draw (0,0) -- (3,0); 26 | \draw[save spath=B, ultra thick, blue] (3,0) -- cycle [insert spath=A]; 27 | \SPathShow{B} 28 | \end{tikzpicture} 29 | \end{document} 30 | -------------------------------------------------------------------------------- /knots_doc.tex: -------------------------------------------------------------------------------- 1 | %\immediate\write18{tex spath3_code.dtx} 2 | \documentclass{ltxdoc} 3 | \usepackage[T1]{fontenc} 4 | \usepackage{trace} 5 | \usepackage{lmodern} 6 | \usepackage{morefloats} 7 | \usepackage{tikz} 8 | \usetikzlibrary{knots,spath3,hobby} 9 | \usepackage[numbered]{hypdoc} 10 | \definecolor{lstbgcolor}{rgb}{0.9,0.9,0.9} 11 | 12 | \usepackage{listings} 13 | \lstloadlanguages{[LaTeX]TeX} 14 | \lstset{ 15 | breakatwhitespace=true, 16 | breaklines=true, 17 | language=[LaTeX]TeX, 18 | basicstyle=\small\ttfamily, 19 | keepspaces=true, 20 | columns=fullflexible 21 | } 22 | 23 | \usepackage{fancyvrb} 24 | 25 | \newenvironment{example} 26 | {\VerbatimEnvironment 27 | \begin{VerbatimOut}{example.out}} 28 | {\end{VerbatimOut} 29 | \begin{center} 30 | \setlength{\parindent}{0pt} 31 | \fbox{\begin{minipage}{.9\linewidth} 32 | \lstinputlisting[]{example.out} 33 | \end{minipage}} 34 | 35 | \fbox{\begin{minipage}{.9\linewidth} 36 | \centering 37 | \input{example.out} 38 | \end{minipage}} 39 | \end{center} 40 | } 41 | 42 | \providecommand*{\url}{\texttt} 43 | \GetFileInfo{spath3.sty} 44 | 45 | \pdfstringdefDisableCommands{% 46 | \def\\{}% 47 | \def\url#1{<#1>}% 48 | } 49 | 50 | \title{The \textsf{knots} Package: Documentation} 51 | \author{Andrew Stacey \\ \url{loopspace@mathforge.org}} 52 | \date{\fileversion~from \filedate} 53 | 54 | \begin{document} 55 | 56 | \maketitle 57 | 58 | \section{Pre-Introduction} 59 | 60 | This library is built on top of a package for manipulating PGF's \emph{soft paths} called \texttt{spath3}. 61 | Version 2.0 of \texttt{spath3} involved considerable reorganisation of the code. 62 | I tried to ensure that this didn't affect this library but it is extremely likely that I wasn't fully successful. 63 | If something that used to work no longer does, please do let me know either by opening an issue on github (\url{https://github.com/loopspace/spath3}) or at the above email. 64 | 65 | That version of \texttt{spath3} also introduced an alternative way of drawing knots which involves breaking the paths at their crossing points and introducing actual gaps. 66 | This makes it easier to do things like have the knots on non-uniform backgrounds, and to style different parts of the knot differently such as illustrating a \(3\)--colouring. 67 | To see how that works, look at the documentation of the \texttt{spath3} TikZ library. 68 | Here's an example of how to draw a knot with that library. 69 | 70 | \begin{example} 71 | \begin{tikzpicture}[ 72 | use Hobby shortcut, 73 | every trefoil component/.style={ultra thick, draw}, 74 | trefoil component 1/.style={red}, 75 | trefoil component 2/.style={blue}, 76 | trefoil component 3/.style={green}, 77 | ] 78 | \path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); 79 | \tikzset{spath/knot={trefoil}{8pt}{1,3,5}} 80 | \end{tikzpicture} 81 | \end{example} 82 | 83 | 84 | \section{Introduction} 85 | 86 | The \Verb+knots+ package is a TikZ library for drawing knot (and similar) diagrams. 87 | It provides a few useful styles and node shapes but its main contribution is the \Verb+knot+ environment. 88 | The \Verb+knot+ environment allows you to draw some strands of a knot (or braid or tangle or whatever -- we shall use the imprecise term ``knot'' to refer to any similar diagram) and then to modify the crossings via a simple interface. 89 | 90 | The main part of this package was developed in response to a question on the \href{http://tex.stackexchange.com}{TeX-SX} site by Jamie Vicary. 91 | The original question was \href{http://tex.stackexchange.com/q/32125/86}{Braid diagrams in TikZ}. 92 | Jamie's comment (quoted below) was the inspiration for the mechanism of the \Verb+knot+ environment. 93 | 94 | \begin{quotation} 95 | [It] would be really cool if it was possible to draw the curves, let TikZ calculate all the intersection points automatically, and then tell it to redraw the intersections according to an under/over specification... do you think this is in the realm of plausibility? 96 | \end{quotation} 97 | 98 | \section{Examples} 99 | 100 | Let us begin with an example. 101 | To use the library, simply load the \Verb+tikz+ package and add \Verb+knots+ to the list of TikZ libraries that you load. 102 | For example, the following in your preamble would work: 103 | 104 | \begin{verbatim} 105 | \usepackage{tikz} 106 | \usetikzlibrary{knots} 107 | \end{verbatim} 108 | 109 | Let's draw a simple tangle (actually a braid). 110 | 111 | \begin{example} 112 | \begin{tikzpicture} 113 | \draw[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 114 | \draw[blue,ultra thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 115 | \end{tikzpicture} 116 | \end{example} 117 | 118 | Now a common way to draw crossings for knots is to draw a gap in the under strand through which the over strand passes. 119 | One way to achieve this in TikZ is to draw the over strand twice, the first time with a thicker line width and the colour of the background. 120 | We'll draw it twice, once with background a different colour to illustrate this. 121 | 122 | \begin{example} 123 | \begin{tikzpicture} 124 | \draw[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 125 | \draw[pink,double=blue,ultra thick,double distance=1.6pt] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 126 | \draw[xshift=5cm,red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 127 | \draw[xshift=5cm,white,double=blue,ultra thick,double distance=1.6pt] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 128 | \end{tikzpicture} 129 | \end{example} 130 | 131 | Now the problem with this method is that there is no way to draw the red and blue paths so that the blue is the over strand at the first crossing and the red at the second. 132 | Either the blue path is always on top (as shown) or the red. 133 | One way to resolve this is to split the paths and draw one of them in segments: 134 | 135 | \begin{example} 136 | \begin{tikzpicture} 137 | \draw[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1); 138 | \draw[white,double=blue,ultra thick,double distance=1.6pt] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 139 | \draw[white,double=red,double distance=1.6pt,ultra thick] (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 140 | \end{tikzpicture} 141 | \end{example} 142 | 143 | Another method (employed by the \Verb+braids+ package) is to break the under path either side of the crossing and not draw it there. 144 | This means that the order of drawing doesn't matter. 145 | 146 | Both of these methods have their drawbacks (particularly for general knots as opposed to the more structured braids) in that they require a detailed knowledge of the pieces of the paths and the positions of the crossings. 147 | As pointed out by Jamie Vicary in the above-{}quoted comment, TikZ should be able to compute these itself. 148 | 149 | That's what this package does. 150 | 151 | Let's do the above example using this package. 152 | The main changes to the drawing are that we use the command \Verb+\strand+ rather than \Verb+\draw+ and we enclose it in the \Verb+knot+ environment. 153 | When initially drawing the strands it is useful to provide the option \Verb+draft mode=strands+. 154 | That's because the detailed computation can take a little time and so it is best only to do it when necessary. 155 | So on first run through we get the following. 156 | 157 | \begin{example} 158 | \begin{tikzpicture} 159 | \begin{knot}[ 160 | draft mode=strands 161 | ] 162 | \strand[red,thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 163 | \strand[blue,thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 164 | \end{knot} 165 | \end{tikzpicture} 166 | \end{example} 167 | 168 | Once we're happy with the positioning of the strands, we change the option \Verb+draft mode=strands+ to \Verb+draft mode=crossings+. 169 | 170 | \begin{example} 171 | \begin{tikzpicture} 172 | \path (2,1.5) (2,-.5); 173 | \begin{knot}[ 174 | draft mode=crossings, 175 | clip width=5, 176 | ] 177 | \strand[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 178 | \strand[blue,ultra thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 179 | \end{knot} 180 | \end{tikzpicture} 181 | \end{example} 182 | 183 | The \Verb+\path (2,1.5) (2,-.5);+ is to extend the bounding box of the picture a little upwards. 184 | The extra pieces are not used when computing the bounding box of the picture so that it doesn't change position on the page. 185 | 186 | The extra information is that the strands and the crossings have been numbered. 187 | The crossings have also been rendered (the \Verb+clip width+ option enlarges the crossing gap to make it more obvious). 188 | Unfortunately, for both crossings the red path is on top. 189 | We need to flip one of these crossings (the first). 190 | To do this, we either use the command \Verb+flipcrossings+ or the \Verb+flip crossing+ key. 191 | 192 | \begin{example} 193 | \begin{tikzpicture} 194 | \path (2,1.5) (2,-.5); 195 | \begin{knot}[ 196 | draft mode=crossings, 197 | clip width=5, 198 | flip crossing=1, 199 | ] 200 | \strand[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 201 | \strand[blue,ultra thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 202 | \end{knot} 203 | \end{tikzpicture} 204 | \end{example} 205 | 206 | Once we're happy with it, we remove the \Verb+draft mode+ option to render it in its final form. 207 | 208 | \begin{example} 209 | \begin{tikzpicture} 210 | \begin{knot}[ 211 | clip width=5, 212 | flip crossing=1, 213 | ] 214 | \strand[red,ultra thick] (0,0) .. controls +(1,0) and +(-1,0) .. (2,1) .. controls +(1,0) and +(-1,0) .. (4,0); 215 | \strand[blue,ultra thick] (0,1) .. controls +(1,0) and +(-1,0) .. (2,0) .. controls +(1,0) and +(-1,0) .. (4,1); 216 | \end{knot} 217 | \end{tikzpicture} 218 | \end{example} 219 | 220 | Here's a more complicated example. 221 | 222 | \begin{example} 223 | \begin{tikzpicture} 224 | \node (A) at (0,4) [draw,minimum width=30pt,minimum height=10pt,thick] {}; 225 | \begin{knot}[ 226 | clip width=5, 227 | clip radius=8pt, 228 | ] 229 | \strand [thick,only when rendering/.style={dashed}] (0,0) 230 | to [out=up, in=down] (-1,1) 231 | to [out=up, in=down] (0,2) 232 | to [out=up, in=down] (-1.2,4) 233 | to [out=up, in=down, looseness=0.7] (0,5.5) 234 | to [out=up, in=down] (-2,7); 235 | \strand [thick] (-1,0) 236 | to [out=up, in=down] (1,2) 237 | to [out=up, in=down] (A.south); 238 | \strand [thick,blue] (1,0) 239 | to [out=up, in=down] (-1,2) 240 | to [out=up, in=down] (1.5,4) 241 | to [out=up, in=right] (0,5.5)to [out=left, in=up] (-2,4) 242 | to [out=down, in=up] (-2,0); 243 | \strand [thick] (A.150) 244 | to [out=up, in=down] (0.7,5.5) 245 | to [out=up, in=down] (0,7); 246 | \strand [thick] (A.30) 247 | to [out=up, in=down] (-1,6) 248 | to [out=up, in=down] (2,7); 249 | \flipcrossings{6,2,9,5,11} 250 | \end{knot} 251 | \end{tikzpicture} 252 | \end{example} 253 | 254 | One feature about this example is the \Verb+only when rendering+ key. 255 | The gaps are made by drawing the strand again with extra thickness in the background colour. 256 | If the \Verb+dashed+ option were always in play for that strand, the gap would be dashed which would spoil the effect. 257 | So the \Verb+only when rendering+ key gathers those options (such as a dash pattern) which should only be applied to the rendered strand and not to the redraw that creates the gap. 258 | 259 | Here's another example. 260 | 261 | \begin{example} 262 | \newcommand{\motif}[1]{ 263 | to ++(180+#1:0.50) arc (270+#1:150+#1:0.15) 264 | to ++( 60+#1:0.50) arc (-30+#1:150+#1:0.15) 265 | to ++(240+#1:0.25) arc (150+#1:330+#1:0.25) 266 | to ++( 60+#1:0.55) arc (150+#1: 30+#1:0.20) 267 | } 268 | \newcommand{\celticknot}{\motif{0}\motif{120}\motif{240}} 269 | \begin{tikzpicture} 270 | \begin{knot}[ 271 | line width=2pt, 272 | line join=round, 273 | clip width=2, 274 | scale=5, 275 | consider self intersections, 276 | ignore endpoint intersections=false, 277 | background color=white, 278 | only when rendering/.style={ 279 | draw=red, 280 | double=white, 281 | double distance=6pt, 282 | line cap=round, 283 | } 284 | ] 285 | \strand (0,0) \celticknot; 286 | \flipcrossings{1,3,6,8,10} 287 | \end{knot} 288 | \end{tikzpicture} 289 | \end{example} 290 | 291 | In this case the strand is a single path. 292 | In the standard case crossings are only considered between separate strands (since the algorithm used by TikZ means that a strand intersects itself infinitely often). 293 | The key \Verb+consider self intersections+ gets round this by ``exploding'' the strand into segments and considering each as a separate path with regard to finding the intersections. 294 | 295 | A path consists of a series of lines and B\'ezier cubics. 296 | The ``explosion'' of a path uses this decomposition. 297 | Unfortunately, even that is not always enough as it is possible for a B\'ezier cubic to self-intersect. 298 | The \Verb+consider self intersections+ also splits these B\'ezier curves in two to ensure that this doesn't happen\footnote{Computing when this is strictly necessary is difficult so it splits more than it needs to to ensure that enough are done.}. 299 | To disable this, use the \Verb+consider self intersections=no splits+ option. 300 | This is the recommended option. 301 | 302 | \begin{example} 303 | \begin{tikzpicture} 304 | \begin{knot}[ 305 | consider self intersections, 306 | draft mode=crossings, 307 | ] 308 | \strand (0,0) .. controls +(3,1) and +(-3,1) .. (1,0); 309 | \end{knot} 310 | \begin{knot}[ 311 | xshift=3cm, 312 | consider self intersections=no splits, 313 | draft mode=crossings, 314 | ] 315 | \strand (0,0) .. controls +(3,1) and +(-3,1) .. (1,0); 316 | \end{knot} 317 | \end{tikzpicture} 318 | \end{example} 319 | 320 | Finally, given that TikZ has to do some heavy computation to find the intersections, it is worth considering using the \Verb+external+ library of TikZ to avoid having to do this on every run. 321 | 322 | \section{Usage} 323 | 324 | \subsection{The \texttt{knot} Environment} 325 | 326 | \DescribeMacro{knot} 327 | \DescribeMacro{\strand} 328 | This package provides a \Verb+knot+ environment for including in a \Verb+tikzpicture+ to render a knot. 329 | This takes an optional argument which is passed to \Verb+\tikzset+ and can be used to configure the knot. 330 | Within that environment, specific strands are defined using the \Verb+\strand+ command (in place of a \Verb+\path+ or \Verb+\draw+). 331 | Further keys can be specified on the strands. 332 | 333 | \DescribeMacro{flip crossing} 334 | \DescribeMacro{\flipcrossings} 335 | Specifying the crossings to be flipped can be done either using the key \Verb+flip crossing+ or the macro \Verb+\flipcrossings+. 336 | The latter can take a comma separated list of crossings to flip. 337 | The former takes a single crossing but can be extended to a comma separated list using the \Verb+.list+ handler as in \Verb+flip crossing/.list={1,2,3}+ (this is what \Verb+\flipcrossings+ does internally). 338 | 339 | \DescribeMacro{\redraw} 340 | There is also a macro \Verb+\redraw+ which redraws a strand in the neighbourhood of a point. 341 | This is effectively what happens for the crossings and can be used to fix something that wasn't done correctly by the main algorithm. 342 | It takes two arguments, the strand number and the point at which to render the strand, as in \Verb+\redraw{2}{(1,1)}+. 343 | 344 | \subsection{Keys} 345 | 346 | The various keys are as follows. 347 | The majority of the keys are in the \Verb+/tikz/knot diagram+ family, but it does its best to pass unknown keys down to \Verb+/tikz/+. 348 | The keys processed by the \Verb+knot+ environment are automatically in this family but the keys processed by the \Verb+\strand+ command are not. 349 | If a standard key (in the option to the \Verb+knot+ environment) doesn't work, try prefixing it with \Verb+/tikz/+ or \Verb+/pgf/+. 350 | 351 | \begin{itemize} 352 | \item \DescribeMacro{every knot diagram} 353 | The style \Verb+every knot diagram+ is executed at the start of the \Verb+knot+ environment. 354 | 355 | Note that it is inside the \Verb+knot diagram+ family so if setting it outside (say, in the preamble) use \Verb+\tikzset{knot diagram/every knot diagram}+. 356 | 357 | \item \DescribeMacro{name} 358 | The crossings of a knot are given coordinates of the form \Verb+ +. 359 | The default name is \Verb+knot+. 360 | The \Verb+name+ key renames it. 361 | 362 | \item \DescribeMacro{every strand} 363 | The contents of \Verb+every strand+ are applied to every strand. 364 | By default this contains the \Verb+draw+ key so if resetting it you should probably ensure that it still has the \Verb+draw+ key. 365 | 366 | Note that it is inside the \Verb+knot diagram+ family so if setting it outside (say, in the preamble) use \Verb+\tikzset{knot diagram/every knot diagram}+. 367 | 368 | \item \DescribeMacro{only when rendering} 369 | The key \Verb+only when rendering={