diff options
Diffstat (limited to 'graphics/pgf/contrib/braids')
-rw-r--r-- | graphics/pgf/contrib/braids/README.txt | 10 | ||||
-rw-r--r-- | graphics/pgf/contrib/braids/braids.pdf | bin | 0 -> 314455 bytes | |||
-rw-r--r-- | graphics/pgf/contrib/braids/braids.tex | 481 | ||||
-rw-r--r-- | graphics/pgf/contrib/braids/braids_code.dtx | 2321 | ||||
-rw-r--r-- | graphics/pgf/contrib/braids/braids_code.pdf | bin | 0 -> 410835 bytes |
5 files changed, 2812 insertions, 0 deletions
diff --git a/graphics/pgf/contrib/braids/README.txt b/graphics/pgf/contrib/braids/README.txt new file mode 100644 index 0000000000..84a8e7c010 --- /dev/null +++ b/graphics/pgf/contrib/braids/README.txt @@ -0,0 +1,10 @@ +---------------------------------------------------------------- +braids --- a style file for drawing braid diagrams with TikZ/PGF +E-mail: loopspace@mathforge.org +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +---------------------------------------------------------------- + +This package defines some commands for drawing braid diagrams with TikZ/PGF. +The initial idea of this package came from a question and answer on the site http://tex.stackexchange.com. + diff --git a/graphics/pgf/contrib/braids/braids.pdf b/graphics/pgf/contrib/braids/braids.pdf Binary files differnew file mode 100644 index 0000000000..5241cd38ee --- /dev/null +++ b/graphics/pgf/contrib/braids/braids.pdf diff --git a/graphics/pgf/contrib/braids/braids.tex b/graphics/pgf/contrib/braids/braids.tex new file mode 100644 index 0000000000..7dab9f0873 --- /dev/null +++ b/graphics/pgf/contrib/braids/braids.tex @@ -0,0 +1,481 @@ +\documentclass{ltxdoc} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage{morefloats} +\usepackage{tikz} +\usepackage{braids} +\usetikzlibrary{braids} +\usepackage[numbered]{hypdoc} +\definecolor{lstbgcolor}{rgb}{0.9,0.9,0.9} + +\usepackage{listings} +\lstloadlanguages{[LaTeX]TeX} +\lstset{breakatwhitespace=true,breaklines=true,language=TeX} + +\usepackage{fancyvrb} + +\newenvironment{example} + {\VerbatimEnvironment + \begin{VerbatimOut}{example.out}} + {\end{VerbatimOut} + \begin{center} + \setlength{\parindent}{0pt} + \fbox{\begin{minipage}{.9\linewidth} + \lstset{breakatwhitespace=true,breaklines=true,language=TeX,basicstyle=\small} + \lstinputlisting[]{example.out} + \end{minipage}} + + \fbox{\begin{minipage}{.9\linewidth} + \input{example.out} + \end{minipage}} +\end{center} +} + +\providecommand*{\url}{\texttt} +\GetFileInfo{tikzlibrarybraids.code.tex} + +\title{The \textsf{braids} Package: Documentation} +\author{Andrew Stacey \\ \texttt{loopspace@mathforge.org}} +\date{\fileversion~from \filedate} + +\begin{document} + +\maketitle + +\begin{center} + \begin{tikzpicture} + \pic[ + line width=1.5pt, + red, + line cap=round, + braid/.cd, + width=.75cm, + height=.5cm, + strand 3/.style={gray,line width=1pt}, + strand 6/.style={gray,line width=1pt}, + strand 7/.style={gray,line width=1pt}, + strand 10/.style={gray,line width=1pt}, + strand 14/.style={gray,line width=1pt}, + strand 15/.style={gray,line width=1pt}, + strand 16/.style={gray,line width=1pt}, + strand 18/.style={gray,line width=1pt}, + ] {braid={s_1-s_4-s_8-s_{12}-s_{16} s_2-s_5-s_7-s_9-s_{13}-s_{15} s_2-s_5-s_7-s_9-s_{15} s_1-s_4-s_8-s_{16} s_1-s_4-s_7-s_9-s_{17} s_2-s_5-s_{17} s_2-s_{13}-s_{16} s_1-s_{12}-s_{15}}}; +\end{tikzpicture} +\end{center} + +\section{Introduction} + +This is a package for drawing braid diagrams using PGF/TikZ. +An example follows. + +\begin{example} +\begin{center} +\begin{tikzpicture} +\pic[ + rotate=90, + braid/.cd, + every strand/.style={ultra thick}, + strand 1/.style={red}, + strand 2/.style={green}, + strand 3/.style={blue}, +] {braid={s_1 s_2^{-1} s_1 s_2^{-1} s_1 s_2^{-1}}}; +\end{tikzpicture} +\end{center} +\end{example} + +\section{TikZ Library Usage} + +Version 2.0 changed the implementation to use the TikZ \Verb+pic+ syntax. +It also converted it to a TikZ library, so to use it put the following in the preamble. + +\begin{verbatim} +\usetikzlibrary{braids} +\end{verbatim} + +(Or add it to the copious list of TikZ libraries that you are already using.) + +\bigskip + +\DescribeMacro{braid} +A braid is specified by the pic name \Verb+braid+. +The usual syntax for this is as follows: + +\Verb+\pic[options] at (coordinate) {braid={braid-word}};+ + +\DescribeMacro{braid-word} +The \Verb+braid-word+ is an expression in the braid group, such as \Verb+s_1 s_2^{-1} s_{3,5}+. +The generator labels are not significant. +If the subscript is a single number, as in \Verb+s_2+, the crossing goes from that number over the next. +If the subscript is two numbers, as in \Verb+s_{2,4}+, the crossing goes from the first over the second, with both the crossing strands passing over all of the intervening strands. +The exponent can be \Verb+1+, \Verb+{-1}+, or missing (in which case it defaults to \Verb+1+, note also that the exponent is read as a \TeX-token so \Verb+{1}+ is also legal). +If the exponent is \(-1\) then the over and under strands swap. + +\begin{itemize} +\item \Verb+s_1+ is strand \(1\) over strand \(2\). +\item \Verb+s_1^{-1}+ is strand \(2\) over strand \(1\). +\item \Verb+s_{1,3}+ is strand \(1\) over strand \(3\), and both are over strand \(2\). +\end{itemize} + +Certain other symbols are allowed in the \Verb+braid-word+ which control the rendering of the braid. +These extras are as follows. + +\begin{enumerate} +\item To get crossings to render at the same height, separate them with a hyphen (note: no check is made to ensure that the crossings can legally be put at the same height; \emph{caveat emptor}). +For example, \Verb+s_1-s_3+. + +\item To draw a \emph{floor} -- which is a rectangle behind the braid occupying some number of levels (the default being one level) -- precede the braid element by a vertical line, as in \Verb+s_1 | s_2+. +The floor is itself a pic which, by default, consists of a rectangle and two horizontal lines. +The rectangle picks up any \Verb+fill+ options and the lines any \Verb+draw+ options that are set in the \Verb+braid/every floor+ and \Verb+braid/floor <n>+ styles. +The \Verb+n+ is the level number, starting at \(1\). + +More general floors can be drawn using the key \Verb+braid/add floor+. +This takes one argument which is a comma separated list of parameters that specifies the position and size floor: +% +\begin{verbatim} +braid/add floor={x,y,width,height,name} +\end{verbatim} +% +The units used are the ``natural'' units of the braid: strand separation and level height. +The \Verb+name+ is optional and if given can be used to style the floor in that the style \Verb+braid/floor <name>+ is applied to that floor. + +Replacing the floor pic will change how it is drawn. +The coordinate system is set up for the floor pic so that the floor is a unit square with lower left corner at the origin. + +\item The identity element can occur in the braid-word. +It is represented by \Verb+1+. +This inserts the identity which corresponds to no crossing. +However, it takes the same amount of space as if there were a crossing. + +\end{enumerate} + +\subsection{Style Options} +\label{sec:picstyleopts} + +There are various keys that change the behaviour or rendering of the braid. +All of these are in the \Verb+/tikz/braid/+ namespace. + +\DescribeMacro{number of strands} The key \Verb+number of strands+ sets the minimum number of strands for the braid. +The number of strands will grow according to the terms in the braid word so this merely sets a lower bound. +If not set, the number of strands will be determined by the terms in the braid word. + +\DescribeMacro{height} +The key \Verb+height+ sets the height of the piece of the braid corresponding to an element in the group. +This can be negative. + +\DescribeMacro{width} +The key \Verb+width+ sets the separation of the strands in the braid. +This can be negative. + +\DescribeMacro{border height} +The key \Verb+border height+ adds a little extra length to the strands at the start and end of the braid. + +\DescribeMacro{gap} +The key \Verb+gap+ is used to determine how much of a gap to leave in the under strand at a crossing. +This should be a number strictly between 0 and .5. +The curve is drawn using a cubic bezier and the gap is in terms of the time parameter, so the gap will not increase exactly proportionally to the value given by this key, though that is a reasonable approximation. + +\DescribeMacro{control factor} +As just said, the parts of the strands involved in a crossing are drawn using a cubic bezier curve. +The control points are vertically above or below their respective end point. +This key determines that vertical separation. +It is multiplied by the \Verb+height+ so that it scales properly. +It can be set to 0 whereupon the strands in the crossing are straight lines. +The default is 0.5. + +\DescribeMacro{nudge factor} +The crossings are not quite placed one after another. +There is a small ``nudge'' between the end of one crossing and the start of another. +Due to the way that the strands are lengthened, if there is no ``nudge'' then some PDF renderers produce slightly strange results at certain magnifications. +This key controls how much that ``nudge'' is, as a factor of the \Verb+height+. +For the aforementioned reason, it should not be set to 0 (the default is 0.05). +Note that this does not change the height of a crossing. +Rather, it nudges the height at which the strands start to cross over. + +\DescribeMacro{every strand, strand <n>} +The style of the strands are controlled by two types of option. +Style options that are set on the \Verb+pic+ are passed to every strand. +It is also possible to add style options to individual strands using the keys \Verb+every strand+ and \Verb+strand <n>+. +The strands are numbered by their starting position. + +\DescribeMacro{every floor, floor <n>} +When a floor is requested behind a crossing, it is rendered as a pic. +These keys control how the floor is styled. + +\subsection{Coordinates and Anchors} + +The braid is littered with coordinates. +Each strand gets a coordinate at each end, and at every level between crossings. +These are labelled and numbered by the initial strand position and the crossing level. +They are also labelled and numbered by the final strand position with the prefix \Verb+rev+. +With a \Verb+name prefix+, the coordinate names look like the following: +% +\begin{verbatim} +<name prefix>-<strand number>-<crossing number> +<name prefix>-rev-<strand number>-<crossing number> +\end{verbatim} +% +The crossing number can also be either \Verb+s+ or \Verb+e+ for the start and end of the strand. +Note that \Verb+-1-0+ and \Verb+-1-s+ are slightly different in that \Verb+s+ includes the border height. + +\DescribeMacro{anchor} +The key \Verb+anchor+ (in the \Verb+braid+ name space) can be used to shift the braid so that a different part of it is at the specified location. +It uses the same syntax as the coordinates, except without the \Verb+<name prefix>-+. +In the following example, the braid is shifted so that where the third strand starts the second level is at the position \Verb+(1,1)+ + +\begin{example} +\begin{center} +\begin{tikzpicture} +\fill[purple] (1,1) circle[radius=3mm]; +\pic[braid/anchor=3-2,rotate=90] at (1,1) {braid={s_2 s_1 s_2 s_1}}; +\end{tikzpicture} +\end{center} +\end{example} + + +\section{Examples} + +Here are more detailed examples. + +\begin{example} +\begin{center} +\begin{tikzpicture} +\pic[ + braid/every floor/.style={fill=yellow}, + braid/floor 1/.style={draw=black,dashed,fill=yellow!50!green}, + line width=2pt, + braid/strand 1/.style={red}, + braid/strand 2/.style={blue}, + braid/strand 3/.style={green}, + braid/add floor={2,4,3,2,a}, + braid/floor a/.style={fill=pink}, + name prefix=braid, +] at (2,0) {braid={| s_1-s_3-s_5 | s_2^{-1}-s_4| s_1-s_4 s_2^{-1} s_1-s_3 s_2^{-1}-s_4^{-1}}}; +\fill[yellow] (2,0) circle (4pt); +\node[at=(braid-3-s),pin=north west:strand 3 start] {}; +\node[at=(braid-3-e),pin=south west:strand 3 end] {}; +\node[at=(braid-rev-3-s),pin=north east:strand 3 (from bottom) start] {}; +\node[at=(braid-rev-3-e),pin=south east:strand 3 (from bottom) end] {}; +\end{tikzpicture} +\end{center} +\end{example} + +\begin{example} +\begin{center} +\begin{tikzpicture} +\pic[ + braid/.cd, + number of strands=3, + line width=8pt, + strand 1/.style={red}, + strand 2/.style={green}, + strand 3/.style={blue}, + gap=0.1, + control factor=0, + nudge factor=0, + name prefix=braid, +] {braid={a_2 a_1 a_2^{-1} a_1}}; +\node[circle,draw,fill=white,inner sep=0pt] at (braid-2-1) {\(+\)}; +\node[circle,draw,fill=white,inner sep=0pt] at (braid-3-1) {\(-\)}; +\node[circle,draw,fill=white,inner sep=0pt] at (braid-2-3) {\(+\)}; +\end{tikzpicture} +\end{center} + +\end{example} + +\newpage + +\section{Original Package Usage (Depreciated)} + +The original version was as a separate package. +This is still included for backwards compatibility. +To use this package, you need to put the following in the preamble. + +\begin{verbatim} +\usepackage{braids} +\end{verbatim} + +\DescribeMacro{\braid} +A braid is specified by the command \Verb+\braid+. +The syntax for this command is as follows: + +\Verb+\braid[style options] (name) at (coordinate) braid-word;+ + +\DescribeMacro{braid-word} +The \Verb+braid-word+ is an expression in the braid group, such as \Verb+s_1 s_2^{-1}+. +The generator labels are not significant. +The exponent can be \Verb+1+, \Verb+{-1}+, or missing (in which case it defaults to \Verb+1+, note also that the exponent is read as a \TeX-token so \Verb+{1}+ is also legal). +Certain other symbols are allowed in the \Verb+braid-word+ which control the rendering of the braid. +These extras are as follows. + +\begin{enumerate} +\item To get crossings to render at the same height, separate them with a hyphen (note: no check is made to ensure that the crossings can legally be put at the same height; \emph{caveat emptor}). + +\item To draw a \emph{floor}, precede the braid element by a vertical line. +What happens then is that when the braid is rendered, the coordinates of the rectangle behind that crossing (wide enough to encompass all the strands) is passed to a command. +The intention is that this command draw something behind the braid. +The command is configurable by a key (see \ref{sec:styleopts}). + +\item The identity element can occur in the braid-word. +It is represented by \Verb+1+. +This inserts the identity which corresponds to no crossing. +However, it takes the same amount of space as if there were a crossing. + +\item Strands can be labelled between crossings. +To do this, the commands \Verb+\label+, \Verb+\olabel+, and \Verb+\clabel+ are provided. +These take three arguments, the first is optional. +The result of this command is to place a node on top of a particular strand between the crossings where the command is given. +The first (optional) argument can be used to pass style options to this node. +The second argument is the strand number. +The third argument is the label text. + +The three commands differ as to how they interpret the strand number. +For \Verb+\olabel+, the strand number is taken to mean the strand that starts at that position. +For \Verb+\clabel+, the strand number is taken to mean the strand that is currently at that position. +The behaviour of \Verb+\label+ is to choose one or other of these depending on whether the key \Verb+strand label by origin+ is true or false. +This key only has an effect at the start of the braid-word; it cannot be reset in the middle. + +\item Style options can be given in the middle of a braid-word by enclosing them in square brackets. +There are not many style options that it makes sense to change in the middle of the braid-word, since the strands are rendered all in one go at the end. + +\item Scoping is handled by using braces. +Thus to change a style only briefly, enclose the desired scope in braces. +\end{enumerate} + +\DescribeMacro{name} +The (optional) \Verb+name+ acts a little like the \Verb+name+ of a TikZ node. +When it is specified, the routine that renders the braid also saves certain coordinates as if they were node anchors. +Specifically, \Verb+coordinate+ nodes are placed at the centre of the braid diagram and at the ends of each strand. +The centre has the label \Verb+name+, the strands are labelled \Verb+name-number-end+ and \Verb+name-rev-number-end+, where \Verb+name+ is the name given to the braid, \Verb+number+ is the number of the strand counting from the left, and \Verb+end+ is either \Verb+s+ for the start or \Verb+e+ for the end. +If the version with \Verb+rev+ is used then the numbers correspond to the \emph{final} positions of the braids. +The name can also be specified with the \Verb+name+ key. + +\DescribeMacro{at} +The (optional) \Verb+at (coordinate)+ syntax positions the braid at the \Verb+coordinate+ in the current picture. +Due to the implementation, the coordinate has to be known at the start, but the width and height of the braid are only known at the end. +Therefore, the braid is positioned so that the start of the first strand is at \Verb+(coordinate)+. +This can also be specified using the \Verb+at+ key. + +\DescribeMacro{style options} +The \Verb+style options+ set the style for the braid strands. +They can be grouped into three types: options that set up the main parameters for the braid, options that set the default style for the strands, and options that set up styles for individual strands. +The options are as follows. + +\subsection{Style Options} +\label{sec:styleopts} + +\DescribeMacro{number of strands} The key \Verb+number of strands+ sets the minimum number of strands for the braid. +The number of strands will grow according to the terms in the braid word so this merely sets a lower bound. +If not set, the number of strands will be determined by the terms in the braid word. + +\DescribeMacro{height} +The key \Verb+height+ sets the height of the piece of the braid corresponding to an element in the group. + +\DescribeMacro{width} +The key \Verb+width+ sets the separation of the strands in the braid. + +\DescribeMacro{border height} +The key \Verb+border height+ adds a little extra length to the strands at the start and end of the braid. + +\DescribeMacro{gap} +The key \Verb+gap+ is used to determine how much of a gap to leave in the under strand at a crossing. +This should be a number strictly between 0 and .5. +The curve is drawn using a cubic bezier and the gap is in terms of the time parameter, so the gap will not increase exactly proportionally to the value given by this key, though that is a reasonable approximation. + +\DescribeMacro{control factor} +As just said, the parts of the strands involved in a crossing are drawn using a cubic bezier curve. +The control points are vertically above or below their respective end point. +This key determines that vertical separation. +It is multiplied by the \Verb+height+ so that it scales properly. +It can be set to 0 whereupon the strands in the crossing are straight lines. +The default is 0.5. + +\DescribeMacro{nudge factor} +The crossings are not quite placed one after another. +There is a small ``nudge'' between the end of one crossing and the start of another. +Due to the way that the strands are lengthened, if there is no ``nudge'' then some PDF renderers produce slightly strange results at certain magnifications. +This key controls how much that ``nudge'' is, as a factor of the \Verb+height+. +For the aforementioned reason, it should not be set to 0 (the default is 0.05). +Note that this does not change the height of a crossing. +Rather, it nudges the height at which the strands start to cross over. + +\DescribeMacro{style strands} +The style of the strands are controlled by two types of option. +Style options that are set on the \Verb+\braid+ command are passed to every strand. +It is also possible to add style options to individual strands using the key \Verb+style strands+. +This takes two options, a comma-delimited list of strand numbers (which could be just a single number) and a list of options to be applied to that strand. +Thus, the syntax is \Verb+style strands={n,m,...}{options}+. +The strands are numbered by their starting position. +Not all of the standard TikZ style options are possible due to the way that the strands are constructed. +Basically, the options that are allowed are those that do not require changing the path or drawing it more than once. + +\DescribeMacro{floor command} +When a floor is requested behind a crossing, the actual way to render it is determined by a command. +This key allows the user to define that command. +The argument to this key should be the code that should be executed for each floor. +To avoid the hassle of getting the number of hashes right, the command should take no arguments. +Rather, the coordinates of the rectangle are saved in to macros \Verb+\floorsx+, \Verb+\floorsy+, \Verb+\floorex+, \Verb+\floorey+ (these macros will expand to something like \Verb+10pt+) and the command should use these to position the drawing. +The default is to draw a line at the top and at the bottom of the rectangle. + +\DescribeMacro{style floors} +\DescribeMacro{style all floors} +In the spirit of separating \emph{style} and \emph{content}, the style options for the floors can be specified separately to the command (of course, they could be built in to the command). +One advantage of this over building them in to the command is to allow them to be overridden for individual floors. +The \Verb+style all floors+ sets up options to be used for \emph{all} floors, whilst the \Verb+style floors={n,m,...}{options}+ sets up options to be used only for the listed floor. +Anything specified in the \Verb+floor command+ will take precedence over both of these. + +Any other style options are passed to the underlying TikZ/PGF system and so may influence how the braid is drawn (but note that not all keys make sense due to the implementation). + + +\section{Examples} + +Here are more detailed examples. + +\begin{example} +\begin{center} +\begin{tikzpicture} +\braid[ + style all floors={fill=yellow}, + style floors={1}{dashed,fill=yellow!50!green}, + floor command={% + \fill (\floorsx,\floorsy) rectangle (\floorex,\floorey); + \draw (\floorsx,\floorsy) -- (\floorex,\floorsy); + }, + line width=2pt, + style strands={1}{red}, + style strands={2}{blue}, + style strands={3}{green} +] (braid) at (2,0) | s_1-s_3-s_5 | s_2^{-1}-s_4| s_1-s_4 s_2^{-1} s_1-s_3 s_2^{-1}-s_4^{-1}; +\fill[yellow] (2,0) circle (4pt); +\fill[purple] (braid) circle (4pt); +\node[at=(braid-3-s),pin=north west:strand 3] {}; +\node[at=(braid-3-e),pin=south west:strand 3] {}; +\node[at=(braid-rev-3-s),pin=north east:strand 3 (from bottom)] {}; +\node[at=(braid-rev-3-e),pin=south east:strand 3 (from bottom)] {}; +\end{tikzpicture} +\end{center} +\end{example} + +\begin{example} +\begin{center} +\begin{tikzpicture} +\braid[ + number of strands=3, + line width=8pt, + style strands={1}{red}, + style strands={2}{green}, + style strands={3}{blue}, + gap=0.1, + control factor=0, + nudge factor=0, + strand label by origin=true, + strand label/.style={circle,draw,fill=white,inner sep=0pt}, + yscale=1] (braid_1) a_2 \label{2}{\(+\)} \clabel{2}{\(-\)} a_1 a_2^{-1} \olabel{2}{\(+\)} a_1; +\end{tikzpicture} +\end{center} + +\end{example} + +\end{document} +% Local Variables: +% tex-output-type: "pdf18" +% End: diff --git a/graphics/pgf/contrib/braids/braids_code.dtx b/graphics/pgf/contrib/braids/braids_code.dtx new file mode 100644 index 0000000000..51a4ee2c60 --- /dev/null +++ b/graphics/pgf/contrib/braids/braids_code.dtx @@ -0,0 +1,2321 @@ +% \iffalse meta-comment +%<*internal> +\iffalse +%</internal> +%<*readme> +---------------------------------------------------------------- +braids --- a style file for drawing braid diagrams with TikZ/PGF +E-mail: loopspace@mathforge.org +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +---------------------------------------------------------------- + +This package defines some commands for drawing braid diagrams with TikZ/PGF. +The initial idea of this package came from a question and answer on the site http://tex.stackexchange.com. +%</readme> +%<*internal> +\fi +\def\nameofplainTeX{plain} +\ifx\fmtname\nameofplainTeX\else + \expandafter\begingroup +\fi +%</internal> +%<*install> +\input l3docstrip.tex +\keepsilent +\askforoverwritefalse +\preamble +---------------------------------------------------------------- +braids --- a style file for drawing braid diagrams with TikZ/PGF +E-mail: loopspace@mathforge.org +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +---------------------------------------------------------------- + +\endpreamble +\postamble + +Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> + +This work may be distributed and/or modified under the +conditions of the LaTeX Project Public License (LPPL), either +version 1.3c of this license or (at your option) any later +version. The latest version of this license is in the file: + +http://www.latex-project.org/lppl.txt + +This work is "maintained" (as per LPPL maintenance status) by +Andrew Stacey. + +This work consists of the files braids.dtx + braids_doc.tex +and the derived files README.txt, + braids.ins, + braids.pdf, + braids.sty, + tikzlibrarybraids.code.tex, + braids_doc.pdf. + +\endpostamble +\usedir{tex/latex/braids} +\generate{ + \file{braids.sty}{\from{\jobname.dtx}{package}} +} +\generate{ + \file{tikzlibrarybraids.code.tex}{\from{\jobname.dtx}{library}} +} +%</install> +%<install>\endbatchfile +%<*internal> +\usedir{source/latex/braids} +\generate{ + \file{\jobname.ins}{\from{\jobname.dtx}{install}} +} +\nopreamble\nopostamble +\usedir{doc/latex/braids} +\generate{ + \file{README.txt}{\from{\jobname.dtx}{readme}} +} +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi +%</internal> +%<*package> +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{braids}[2011/10/18 v1.1 Tikz/PGF commands for drawing braid diagrams] +%</package> +%<*driver> +\documentclass{l3doc} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage{tikz} +\usepackage{braids} +\usetikzlibrary{braids} + +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \CheckSum{1949} +% +% \CharacterTable +% {Upper-case \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 +% Lower-case \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 +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \changes{1.0}{2011/05/03}{Converted to DTX file} +% \changes{1.1}{2011/05/03}{Extended syntax} +% \changes{2.0}{2019/03/20}{Converted TikZ library} +% +% \DoNotIndex{\newcommand,\newenvironment} +% +% \GetFileInfo{tikzlibrarybraids.code.tex} +% \title{The \textsf{braids} package: codebase} +% \author{Andrew Stacey \\ \texttt{loopspace@mathforge.org}} +% \date{\fileversion~from \filedate} +% +% \maketitle +% +% \section{Introduction} +% +% This is a package for drawing braid diagrams using PGF/TikZ. +% Its inspiration was a question and answer on the website \texttt{http://tex.stackexchange.com}. +% +% \section{History} +% +% \begin{itemize} +% \item v1.0 First public release. +% +% \item v1.1 Added ability to configure the gap size, the control points, and the ``nudge''. +% Added ability to add labels to strands between crossings. +% +% \item v2 Reimplemented as TikZ library rather than a standalone package. +% \end{itemize} +% \StopEventually{} +% +% \section{Implementation} +% +% \iffalse +%<*package> +% \fi +% +% Issue a notice that this is a depreciated version of the braids package. +% \begin{macrocode} +\PackageWarning{braids}{% + This package has been reimplemented as a TikZ library; if starting with a fresh document, please consider using that instead.% +}% +% \end{macrocode} +% +% \begin{macro}[internal]{\ge@addto@macro} +% This is an expanded version of \Verb+\g@addto@macro+. +% Namely, it adds the \emph{expansion} of the second argument to the first. +% \begin{macrocode} +\long\def\ge@addto@macro#1#2{% + \begingroup + \toks@\expandafter\expandafter\expandafter{\expandafter#1#2}% + \xdef#1{\the\toks@}% + \endgroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\braid} +% This is the user command. +% We start a group to ensure that all our assignments are local, and then call our initialisation code. +% The optional argument is for any keys to be set. +% \begin{macrocode} +\newcommand{\braid}[1][]{% + \begingroup + \braid@start{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@process} +% This is the token swallower. +% This takes the next token on the braid specification and passes it to the handler command (in the macro \Verb+\braid@token+) which decides what to do next. +% (Incidentally, the code here is heavily influenced by TikZ. +% That's probably not very surprising.) +% \begin{macrocode} +\def\braid@process{% + \afterassignment\braid@handle\let\braid@token=% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@process@start} +% This is a variant of \Verb+\braid@process+ which is used at the start where we might have a few extra bits and pieces before the braid itself starts. +% Specifically, we test for the \Verb+at+ and \Verb+(name)+ possibilities. +% \begin{macrocode} +\def\braid@process@start{% + \afterassignment\braid@handle@start\let\braid@token=% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@handle@start} +% This is the handler in use at the start. +% It looks for the tokens \Verb+a+ or \Verb+(+ which (might) signal the start of an \Verb+at (coordinate)+ or \Verb+(name)+. +% If we get anything else (modulo spaces) we decide that we've reached the end of the initialisation stuff and it is time to get started on the braid itself. +% \begin{macrocode} +\def\braid@handle@start{% + \let\braid@next=\braid@handle + \ifx\braid@token a +% \end{macrocode} +% We got an \Verb+a+ so we might have an \Verb+at (coordinate)+ +% \begin{macrocode} + \let\braid@next=\braid@maybe@locate + \else + \ifx\braid@token(%) +% \end{macrocode} +% We got an \Verb+(+ so we have a name +% \begin{macrocode} + \iffalse)\fi %Indentation hack! + \let\braid@next=\braid@assign@name + \else + \ifx\braid@token\@sptoken +% \end{macrocode} +% Space; boring, redo from start +% \begin{macrocode} + \let\braid@next=\braid@process@start + \fi + \fi + \fi + \braid@next% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@handle} +% This is the main handler for parsing the braid word. +% It decides what action to take depending on what the token is. +% We have to be a bit careful with catcodes, some packages set +% \Verb+;+ and \Verb+|+ to be active. +% We should probably also be careful with \Verb+^+ and \Verb+_+. +% \begin{macrocode} +\let\braid@semicolon=; +\let\braid@bar=| +\def\braid@handle{% + \let\braid@next=\braid@process +% \end{macrocode} +% Start by checking our catcodes to see what we should check against +% \begin{macrocode} + \ifnum\the\catcode`\;=\active + \expandafter\let\expandafter\braid@semicolon\tikz@activesemicolon + \fi + \ifnum\the\catcode`\|=\active + \expandafter\let\expandafter\braid@bar\tikz@activebar + \fi + \ifx\braid@token\braid@semicolon +% \end{macrocode} +% Semicolon, means that we're done reading our braid. +% It's time to render it. +% \begin{macrocode} + \let\braid@next=\braid@render + \else + \ifx\braid@token^ +% \end{macrocode} +% Superscript character, the next token tells us whether it's an over-crossing or an under-crossing. +% \begin{macrocode} + \let\braid@next=\braid@sup + \else + \ifx\braid@token_ +% \end{macrocode} +% Subscript character, the next token tells us which strands cross. +% \begin{macrocode} + \let\braid@next=\braid@sub + \else + \ifx\braid@token- +% \end{macrocode} +% Hyphen, this is so that we can have more than one crossing on the same level. +% \begin{macrocode} + \braid@increase@levelfalse + \else + \ifx\braid@token1% +% \end{macrocode} +% 1: this means the ``identity'' crossing, so no crossing here. +% Increase the level, unless overriden, and add to the label. +% \begin{macrocode} + \ifbraid@increase@level + \stepcounter{braid@level} + \fi + \braid@increase@leveltrue + \ge@addto@macro\braid@label{\braid@token}% + \else + \ifx\braid@token[% +% \end{macrocode} +% Open bracket, this means we have some more options to process. +% \begin{macrocode} + \let\braid@next=\braid@process@options + \else + \ifx\braid@token\braid@bar +% \end{macrocode} +% Bar, this tells us that we want a ``floor'' at this point. +% \begin{macrocode} + \edef\braid@tmp{,\expandafter\the\value{braid@level}}% + \ge@addto@macro\braid@floors\braid@tmp% + \else + \ifx\braid@token\bgroup +% \end{macrocode} +% Begin group, which we reinterpret as begining a scope. +% \begin{macrocode} + \braid@beginscope + \else + \ifx\braid@token\egroup +% \end{macrocode} +% End group, which ends the scope +% \begin{macrocode} + \braid@endscope + \else + \ifx\braid@token\braid@olabel@strand + \let\braid@next=\braid@olabel@strand + \else + \ifx\braid@token\braid@clabel@strand + \let\braid@next=\braid@clabel@strand + \else +% \end{macrocode} +% Otherwise, we add the token to the braid label. +% \begin{macrocode} + \ge@addto@macro\braid@label{\braid@token}% + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \braid@next% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@maybe@locate} +% If we got an \Verb+a+ token in the \Verb+\braid@handle@start+ then it \emph{might} mean we're looking at \Verb+at (coordinate)+ or it might mean that the user has decided to use \Verb+a+ as the braid parameter. +% So we examine the next token for a \Verb+t+. +% \begin{macrocode} +\def\braid@maybe@locate{% + \afterassignment\braid@@maybe@locate\let\braid@token=% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@@maybe@locate} +% This is where we test for \Verb+t+ and act appropriately. +% \begin{macrocode} +\def\braid@@maybe@locate{% + \let\braid@next=\braid@handle + \ifx\braid@token t + \let\braid@next=\braid@find@location + \fi + \braid@next% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@find@location} +% This macro starts us looking for a coordinate. +% \begin{macrocode} +\def\braid@find@location{% + \afterassignment\braid@@find@location\let\braid@token=% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@@find@location} +% This is the test for the start of a coordinate. +% If we get a \Verb+(+ that means we've reached the coordinate. +% A space means ``carry on''. +% Anything else is a (non-fatal) error. +% \begin{macrocode} +\def\braid@@find@location{% + \let\braid@next=\braid@location@error + \ifx\braid@token(%) + \let\braid@next=\braid@locate + \else + \ifx\braid@token\@sptoken + \let\braid@next=\braid@find@location + \fi + \fi + \braid@next% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@location@error} +% This is our error message for not getting a location. +% \begin{macrocode} +\def\braid@location@error{% + \PackageWarning{braids}{Could not figure out location for braid}% + \braid@process@start% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@locate} +% If we reached a \Verb+(+ when looking for a coordinate, everything up to the next \Verb+)+ is that coordinate. +% Then we parse the coordinate and call the relocation macro. +% \begin{macrocode} +\def\braid@locate#1){% + \tikz@scan@one@point\braid@relocate(#1)% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@relocate} +% This is the macro that actually does the relocation. +% \begin{macrocode} +\def\braid@relocate#1{% + #1\relax + \advance\pgf@x by -\braid@width + \pgftransformshift{\pgfqpoint{\pgf@x}{\pgf@y}} + \braid@process@start% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@assign@name} +% This macro saves our name. +% \begin{macrocode} +\def\braid@assign@name#1){% + \def\braid@name{#1}% + \braid@process@start% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@process@options} +% The intention of this macro is to allow setting of style options mid-braid. +% (At present, this wouldn't make a lot of sense.) +% \begin{macrocode} +\def\braid@process@options#1]{% + \tikzset{#1}% + \braid@process% +} +% \end{macrocode} +% \end{macro} +% +% The next macros handle the actual braid elements. +% Everything has to have a subscript, but the superscript is optional and can come before or after the subscript. +% +% \begin{macro}[internal]{\braid@sup} +% This handles braid elements of the form \Verb+a^{-1}_2+. +% \begin{macrocode} +\def\braid@sup#1_#2{% + \g@addto@macro\braid@label{_{#2}^{#1}}% + \braid@add@crossing{#2}{#1}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@sub} +% \begin{macrocode} +% This handles braid elements of the form \Verb+a_1+ or \Verb+a_1^{-1}+. +\def\braid@sub#1{% + \@ifnextchar^{\braid@@sub{#1}}% + {\g@addto@macro\braid@label{_{#1}}\braid@add@crossing{#1}{1}}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@@sub} +% Helper macro for \Verb+\braid@sub+. +% \begin{macrocode} +\def\braid@@sub#1^#2{% + \g@addto@macro\braid@label{_{#1}^{#2}}% + \braid@add@crossing{#1}{#2}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@ne} +% Remember what \Verb+1+ looks like for testing against. +% \begin{macrocode} +\def\braid@ne{1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@add@crossing} +% This is the macro which adds the crossing to the current list of strands. +% The strands are stored as \emph{soft paths} (see the TikZ/PGF documentation). +% So this selects the right strands and then extends them according to the crossing type. +% \begin{macrocode} +\def\braid@add@crossing#1#2{% +% \end{macrocode} +% Our crossing type, which is \Verb+#2+, is one of \Verb+1+ or \Verb+-1+. +% Our strands are \Verb+#1+ and \Verb-#1+1-. +% \begin{macrocode} + \edef\braid@crossing@type{#2}% + \edef\braid@this@strand{#1}% + \pgfmathtruncatemacro{\braid@next@strand}{#1+1} +% \end{macrocode} +% Increment the level counter, if requested. +% The controls whether the crossing is on the same level as the previous one or is one level further on. +% \begin{macrocode} + \ifbraid@increase@level + \stepcounter{braid@level} + \fi +% \end{macrocode} +% Default is to request increment so we set it for next time. +% \begin{macrocode} + \braid@increase@leveltrue +% \end{macrocode} +% Now we figure out the coordinates of the crossing. +% \Verb+(\braid@tx,\braid@ty)+ is the top-left corner (assuming the braid flows down the page). +% \Verb+(\braid@nx,\braid@ny)+ is the bottom-right corner (assuming the braid flows down the page). +% We start by setting \Verb+(\braid@tx,\braid@ty)+ according to the level and strand number, then shift \Verb+\braid@ty+ by \Verb+\braid@eh+ which is the ``edge height'' (the little extra at the start and end of each strand). +% Then from these values, we set \Verb+(\braid@nx,\braid@ny)+ by adding on the appropriate amount. +% The heights \Verb+\braid@cy+ and \Verb+\braid@dy+ are for the control points for the strands as they cross. +% They're actually the same height, but using two gives us the possibility of changing them independently in a later version of this package. +% Lastly, we bring \Verb+\braid@ty+ and \Verb+\braid@ny+ towards each other just a little so that there is ``clear water'' between subsequent crossings (makes it look a bit better if the same strand is used in subsequent crossings). +% \begin{macrocode} + \braid@tx=\braid@this@strand\braid@width + \braid@ty=\value{braid@level}\braid@height + \advance\braid@ty by \braid@eh + \braid@nx=\braid@tx + \braid@ny=\braid@ty + \advance\braid@nx by \braid@width + \advance\braid@ny by \braid@height + \advance\braid@ty by \braid@nf\braid@height + \advance\braid@ny by -\braid@nf\braid@height + \braid@cy=\braid@ty + \braid@dy=\braid@ny + \advance\braid@cy by \braid@cf\braid@height + \advance\braid@dy by -\braid@cf\braid@height +% \end{macrocode} +% Now we try to find a starting point for the strand ending here. +% We might not have used this strand before, so it might not exist. +% \begin{macrocode} + \expandafter\let\expandafter\braid@this@path@origin% + \csname braid@strand@\braid@this@strand @origin\endcsname +% \end{macrocode} +% If we haven't seen this strand before, that one will be \Verb+\relax+. +% \begin{macrocode} +\ifx\braid@this@path@origin\relax +% \end{macrocode} +% Haven't seen this strand before, so initialise it. +% Record the initial position of the strand. +% \begin{macrocode} + \let\braid@this@path@origin\braid@this@strand +% \end{macrocode} +% Start a new soft path. +% \begin{macrocode} + \pgfsyssoftpath@setcurrentpath{\@empty} + \pgfpathmoveto{\pgfpoint{\braid@tx}{0pt}} +% \end{macrocode} +% Save the path as \Verb+\braid@this@path+. +% \begin{macrocode} + \pgfsyssoftpath@getcurrentpath{\braid@this@path} + \else +% \end{macrocode} +% We have seen this before, so we simply copy the associated path in to \Verb+\braid@this@path+. +% \begin{macrocode} + \expandafter\let\expandafter\braid@this@path% + \csname braid@strand@\braid@this@path@origin\endcsname + \fi +% \end{macrocode} +% Now we do the same again with the other strand in the crossing. +% \begin{macrocode} + \expandafter\let\expandafter\braid@next@path@origin% + \csname braid@strand@\braid@next@strand @origin\endcsname + \ifx\braid@next@path@origin\relax + \let\braid@next@path@origin\braid@next@strand + \pgfsyssoftpath@setcurrentpath{\@empty} + \pgfpathmoveto{\pgfpoint{\braid@nx}{0pt}} + \pgfsyssoftpath@getcurrentpath{\braid@next@path} + \else + \expandafter\let\expandafter\braid@next@path% + \csname braid@strand@\braid@next@path@origin\endcsname + \fi +% \end{macrocode} +% Now that we have the paths for our two strands, we extend them to the next level. +% We start by selecting the first path. +% \begin{macrocode} + \pgfsyssoftpath@setcurrentpath{\braid@this@path} +% \end{macrocode} +% Draw a line down to the current level, note that this line is always non-trivial since we shifted the corners of the crossing in a little. +% \begin{macrocode} + \pgfpathlineto{\pgfqpoint{\braid@tx}{\braid@ty}} +% \end{macrocode} +% Curve across to the next position. +% Depending on the crossing type, we either have a single curve or we have to break it in two. +% Our gap is to interrupt at times determined by the gap key. +% \begin{macrocode} +\pgfmathsetmacro{\braid@gst}{0.5 - \pgfkeysvalueof{/pgf/braid/gap}}% +\pgfmathsetmacro{\braid@gend}{0.5 + \pgfkeysvalueof{/pgf/braid/gap}}% +\ifx\braid@crossing@type\braid@over@cross +% \end{macrocode} +% We're on the overpass, so just one curve needed. +% \begin{macrocode} + \pgfpathcurveto{\pgfqpoint{\braid@tx}{\braid@cy}}% + {\pgfqpoint{\braid@nx}{\braid@dy}}% + {\pgfqpoint{\braid@nx}{\braid@ny}} +\else +% \end{macrocode} +% We're on the underpass, so we need to interrupt our path to allow the other curve to go past. +% \begin{macrocode} + \pgfpathcurvebetweentimecontinue{0}{\braid@gst}% + {\pgfqpoint{\braid@tx}{\braid@ty}}% + {\pgfqpoint{\braid@tx}{\braid@cy}}% + {\pgfqpoint{\braid@nx}{\braid@dy}}% + {\pgfqpoint{\braid@nx}{\braid@ny}}% + \pgfpathcurvebetweentime{\braid@gend}{1}% + {\pgfqpoint{\braid@tx}{\braid@ty}}% + {\pgfqpoint{\braid@tx}{\braid@cy}}% + {\pgfqpoint{\braid@nx}{\braid@dy}}% + {\pgfqpoint{\braid@nx}{\braid@ny}} +\fi +% \end{macrocode} +% We're done with this path, so now we save it. +% \begin{macrocode} + \pgfsyssoftpath@getcurrentpath{\braid@this@path} +% \end{macrocode} +% Now do the same with the second path. +% \begin{macrocode} + \pgfsyssoftpath@setcurrentpath{\braid@next@path} + \pgfpathlineto{\pgfqpoint{\braid@nx}{\braid@ty}} +\ifx\braid@crossing@type\braid@over@cross + \pgfpathcurvebetweentimecontinue{0}{\braid@gst}% + {\pgfqpoint{\braid@nx}{\braid@ty}}% + {\pgfqpoint{\braid@nx}{\braid@cy}}% + {\pgfqpoint{\braid@tx}{\braid@dy}}% + {\pgfqpoint{\braid@tx}{\braid@ny}} + \pgfpathcurvebetweentime{\braid@gend}{1}% + {\pgfqpoint{\braid@nx}{\braid@ty}}% + {\pgfqpoint{\braid@nx}{\braid@cy}}% + {\pgfqpoint{\braid@tx}{\braid@dy}}% + {\pgfqpoint{\braid@tx}{\braid@ny}} +\else + \pgfpathcurveto{\pgfqpoint{\braid@nx}{\braid@cy}}% + {\pgfqpoint{\braid@tx}{\braid@dy}}% + {\pgfqpoint{\braid@tx}{\braid@ny}} +\fi + \pgfsyssoftpath@getcurrentpath{\braid@next@path} +% \end{macrocode} +% Now save the paths to their proper macros again. +% \begin{macrocode} + \expandafter\let% + \csname braid@strand@\braid@this@path@origin \endcsname% + \braid@this@path + \expandafter\let% + \csname braid@strand@\braid@next@path@origin \endcsname% + \braid@next@path +% \end{macrocode} +% Now update the origins +% \begin{macrocode} + \expandafter\let% + \csname braid@strand@\braid@this@strand @origin\endcsname% + \braid@next@path@origin + \expandafter\let% + \csname braid@strand@\braid@next@strand @origin\endcsname% + \braid@this@path@origin +% \end{macrocode} +% increment the strand counter, if necessary +% \begin{macrocode} + \pgfmathparse{\value{braid@strands} < \braid@next@strand ? + "\noexpand\setcounter{braid@strands}{\braid@next@strand}" : ""} + \pgfmathresult +% \end{macrocode} +% And merrily go on our way with the next bit of the braid specification. +% \begin{macrocode} + \braid@process% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@olabel@strand} +% This macro allows us to label a strand just before a crossing. +% The first argument is the strand number at that particular crossing and the second is the label. +% We also save the current height. +% This version takes the strand number as meaning the \emph{original} ordering. +% \begin{macrocode} +\newcommand{\braid@olabel@strand}[3][]{% + \edef\braid@tmp{{\the\value{braid@level}}}% + \expandafter\ifx\csname braid@strand@#2@origin\endcsname\relax + \g@addto@macro\braid@tmp{{#2}}% + \else + \edef\braid@tmpa{{\csname braid@strand@#2@origin\endcsname}}% + \ge@addto@macro\braid@tmp{\braid@tmpa}% + \fi + \g@addto@macro\braid@tmp{{#3}{#1}}% + \ge@addto@macro{\braid@strand@labels}{\braid@tmp}% + \braid@process% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@clabel@strand} +% This macro allows us to label a strand just before a crossing. +% The first argument is the strand number at that particular crossing and the second is the label. +% We also save the current height. +% This version takes the strand number as meaning the \emph{current} ordering. +% \begin{macrocode} +\newcommand{\braid@clabel@strand}[3][]{% + \edef\braid@tmp{{\the\value{braid@level}}}% + \g@addto@macro\braid@tmp{{#2}{#3}{#1}}% + \ge@addto@macro{\braid@strand@labels}{\braid@tmp}% + \braid@process% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@floors@trim} +% The list of floors, if given, will start with a superfluous comma. +% This removes it. +% \begin{macrocode} +\def\braid@floors@trim,{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@render@floor} +% This is the default rendering for floors: it draws a rectangle. +% \begin{macrocode} +\def\braid@render@floor{% + \draw (\floorsx,\floorsy) rectangle (\floorex,\floorey); +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@render@strand@labels} +% This starts rendering the labels on the strands at the crossings. +% \begin{macrocode} +\def\braid@render@strand@labels#1{% + \def\braid@tmp{#1}% + \ifx\braid@tmp\pgfutil@empty + \let\braid@next=\pgfutil@gobble + \else + \let\braid@next=\braid@@render@strand@labels + \fi + \braid@next{#1}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@@render@strand@labels} +% This is the actual renderer. +% \begin{macrocode} +\def\braid@@render@strand@labels#1#2#3#4{% + \begingroup + \pgfscope + \let\tikz@options=\pgfutil@empty + \let\tikz@mode=\pgfutil@empty + \let\tik@transform=\pgfutil@empty + \let\tikz@fig@name=\pgfutil@empty + \tikzset{/pgf/braid/strand label,#4}% + \braid@nx=#2\braid@width + \braid@ny=#1\braid@height + \advance\braid@ny by \braid@eh + \advance\braid@ny by \braid@height + \pgftransformshift{\pgfqpoint{\braid@nx}{\braid@ny}}% + \tikz@options + \setbox\pgfnodeparttextbox=\hbox% + \bgroup% + \tikzset{every text node part/.try}% + \ifx\tikz@textopacity\pgfutil@empty% + \else% + \pgfsetfillopacity{\tikz@textopacity}% + \pgfsetstrokeopacity{\tikz@textopacity}% + \fi% + \pgfinterruptpicture% + \tikz@textfont% + \ifx\tikz@text@width\pgfutil@empty% + \else% + \begingroup% + \pgfmathsetlength{\pgf@x}{\tikz@text@width}% + \pgfutil@minipage[t]{\pgf@x}\leavevmode\hbox{}% + \tikz@text@action% + \fi% + \tikz@atbegin@node% + \bgroup% + \aftergroup\unskip% + \ifx\tikz@textcolor\pgfutil@empty% + \else% + \pgfutil@colorlet{.}{\tikz@textcolor}% + \fi% + \pgfsetcolor{.}% + \setbox\tikz@figbox=\box\pgfutil@voidb@x% + \tikz@uninstallcommands% + \tikz@halign@check% + \ignorespaces% + #3 + \egroup + \tikz@atend@node% + \ifx\tikz@text@width\pgfutil@empty% + \else% + \pgfutil@endminipage% + \endgroup% + \fi% + \endpgfinterruptpicture% + \egroup% + \ifx\tikz@text@width\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@width}% + \wd\pgfnodeparttextbox=\pgf@x% + \fi% + \ifx\tikz@text@height\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@height}% + \ht\pgfnodeparttextbox=\pgf@x% + \fi% + \ifx\tikz@text@depth\pgfutil@empty% + \else% + \pgfmathsetlength{\pgf@x}{\tikz@text@depth}% + \dp\pgfnodeparttextbox=\pgf@x% + \fi% + \pgfmultipartnode{\tikz@shape}{\tikz@anchor}{\tikz@fig@name}{% + {\begingroup\tikz@finish}% + }% + \endpgfscope + \endgroup + \braid@render@strand@labels% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@render} +% This is called at the end of the braid and it renders the braids and floors according to whatever has been built up up to now. +% \begin{macrocode} +\def\braid@render{ +% \end{macrocode} +% Check for floors since we do them first. +% \begin{macrocode} + \ifx\braid@floors\@empty + \else +% \end{macrocode} +% Have some floors, start a scope and prepare to render them. +% \begin{macrocode} + \pgfsys@beginscope +% \end{macrocode} +% Clear the path (just to be sure). +% \begin{macrocode} + \pgfsyssoftpath@setcurrentpath{\empty} +% \end{macrocode} +% Trim the initial comma off the list of floors. +% \begin{macrocode} + \edef\braid@floors{\expandafter\braid@floors@trim\braid@floors} +% \end{macrocode} +% Initialise our horizontal coordinates. +% \begin{macrocode} + \braid@tx=\braid@width + \advance\braid@tx by \braid@eh + \braid@nx=\value{braid@strands}\braid@width + \advance\braid@nx by -\braid@eh +% \end{macrocode} +% Loop over the list of floors. +% \begin{macrocode} + \foreach \braid@f in \braid@floors { + \pgfsys@beginscope +% \end{macrocode} +% Figure out the vertical coordinates for the current floor. +% \begin{macrocode} + \braid@ty=\braid@f\braid@height + \advance\braid@ty by \braid@eh + \advance\braid@ty by \braid@height + \braid@ny=\braid@ty + \advance\braid@ny by \braid@height +% \end{macrocode} +% Save the coordinates for use in the floor rendering macro. +% \begin{macrocode} + \edef\floorsx{\the\braid@tx} + \edef\floorsy{\the\braid@ty} + \edef\floorex{\the\braid@nx} + \edef\floorey{\the\braid@ny} + \let\tikz@options=\pgfutil@empty +% \end{macrocode} +% Load general floor style options. +% \begin{macrocode} + \expandafter\tikzset\expandafter{\braid@floors@style} +% \end{macrocode} +% Load any style options specific to this floor. +% We're actually offset by 2 from what the user thinks the floor level is. +% \begin{macrocode} + \pgfmathtruncatemacro{\braid@ff}{\braid@f+2} +% \end{macrocode} +% Load the relevant floor style, if it exists. +% \begin{macrocode} + \expandafter\let\expandafter\braid@floor@style% + \csname braid@options@floor@\braid@ff\endcsname + \ifx\braid@floor@style\relax + \else +% \end{macrocode} +% There is a floor style for this level, so process it. +% \begin{macrocode} + \expandafter\tikzset\expandafter{\braid@floor@style}% + \fi +% \end{macrocode} +% The \Verb+\tikzset+ just parses the options, we need to call \Verb+\tikz@options+ to actually set them. +% \begin{macrocode} +\tikz@options +% \end{macrocode} +% Now we call the rendering code. +% \begin{macrocode} +\braid@render@floor +% \end{macrocode} +% Done! +% End the scope for \emph{this} floor and go again. +% \begin{macrocode} +\pgfsys@endscope + } +% \end{macrocode} +% Done rendering floors, end the scope. +% \begin{macrocode} + \pgfsys@endscope + \fi +% \end{macrocode} +% Finished with floors (if we had them), now get on with the strands. +% \begin{macrocode} + \stepcounter{braid@level} + \foreach \braid@k in {1,...,\value{braid@strands}} { +% \end{macrocode} +% Start a local scope to ensure we don't mess with other braids +% \begin{macrocode} + \pgfsys@beginscope +% \end{macrocode} +% Default is to draw each braid +% \begin{macrocode} + \tikz@mode@drawtrue% + \let\tikz@mode=\pgfutil@empty + \let\tikz@options=\pgfutil@empty +% \end{macrocode} +% (x,y) coordinates of bottom of strand +% \begin{macrocode} + \braid@tx=\braid@k\braid@width + \braid@ty=\value{braid@level}\braid@height + \advance\braid@ty by 2\braid@eh +% \end{macrocode} +% Try to find the starting point of this strand +% \begin{macrocode} + \expandafter\let\expandafter\braid@path@origin% + \csname braid@strand@\braid@k @origin\endcsname + \ifx\braid@path@origin\relax +% \end{macrocode} +% If that doesn't exist, we'll just draw a straight line +% so we move to the top of the current position +% \begin{macrocode} + \pgfsyssoftpath@setcurrentpath{\@empty} + \pgfpathmoveto{\pgfqpoint{\braid@tx}{0pt}} + \let\braid@path@origin\braid@k + \else +% \end{macrocode} +% If the path does exist, we load it +% \begin{macrocode} + \expandafter\let\expandafter\braid@path% + \csname braid@strand@\braid@path@origin\endcsname + \pgfsyssoftpath@setcurrentpath{\braid@path} + \fi +% \end{macrocode} +% Extend the path to the bottom +% \begin{macrocode} + \pgflineto{\pgfqpoint{\braid@tx}{\braid@ty}} +% \end{macrocode} +% Load common style options +% \begin{macrocode} + \expandafter\tikzset\expandafter{\braid@style} +% \end{macrocode} +% Load any style options specific to this strand +% \begin{macrocode} + \expandafter\let\expandafter\braid@style% + \csname braid@options@strand@\braid@path@origin\endcsname + \ifx\braid@style\relax + \else + \expandafter\tikzset\expandafter{\braid@style} + \fi +\braid@options + \tikz@mode + \tikz@options +% \end{macrocode} +% This is the command that actually draws the strand. +% \begin{macrocode} + \edef\tikz@temp{\noexpand\pgfusepath{% + \iftikz@mode@draw draw\fi% + }}% + \tikz@temp +% \end{macrocode} +% If our braid has a name, we label the ends of the strand. +% \begin{macrocode} +\ifx\braid@name\pgfutil@empty +\else +% \end{macrocode} +% Label the ends of the strand. +% \begin{macrocode} +\coordinate (\braid@name-\braid@path@origin-e) at (\braid@tx,\braid@ty); +\coordinate (\braid@name-rev-\braid@k-e) at (\braid@tx,\braid@ty); +\braid@nx=\braid@path@origin\braid@width +\coordinate (\braid@name-\braid@path@origin-s) at (\braid@nx,0pt); +\coordinate (\braid@name-rev-\braid@k-s) at (\braid@nx,0pt); +\fi +% \end{macrocode} +% Done with this strand, close the scope and do the next one. +% \begin{macrocode} + \pgfsys@endscope + } +% \end{macrocode} +% If our braid has a name, we also want to label the centre. +% \begin{macrocode} + \ifx\braid@name\pgfutil@empty + \else + \braid@tx=\value{braid@strands}\braid@width + \braid@ty=\value{braid@level}\braid@height + \advance\braid@ty by 2\braid@eh + \advance\braid@tx by \braid@width + \braid@tx=.5\braid@tx + \braid@ty=.5\braid@ty + \coordinate (\braid@name) at (\braid@tx,\braid@ty); + \fi +% \end{macrocode} +% Now we label the strands if needed. +% \begin{macrocode} + \ifx\braid@strand@labels\pgfutil@empty + \else + \expandafter\braid@render@strand@labels\braid@strand@labels{}% + \fi +% \end{macrocode} +% All done now, close the scope and end the group (which was opened right at the start). +% \begin{macrocode} + \pgfsys@endscope + \endgroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\braid@start} +% This starts off the braid, initialising a load of stuff. +% We start a PGF scope, set the level to \(-1\), the label, floors, and name to empty, process any options we're given, and save certain lengths for later use.. +% \begin{macrocode} +\def\braid@start#1{% + \pgfsys@beginscope + \setcounter{braid@level}{-1}% + \let\braid@label\@empty + \let\braid@strand@labels\@empty + \let\braid@floors\@empty + \let\braid@name\empty + \let\clabel=\braid@clabel@strand + \let\olabel=\braid@olabel@strand + \pgfkeys{/pgf/braid/.cd,#1}% + \ifbraid@strand@labels@origin + \let\label=\braid@olabel@strand + \else + \let\label=\braid@clabel@strand + \fi + \let\braid@options\tikz@options + \tikz@transform + \setcounter{braid@strands}{% + \pgfkeysvalueof{/pgf/braid/number of strands}}% + \braid@width=\pgfkeysvalueof{/pgf/braid/width}% + \braid@height=\pgfkeysvalueof{/pgf/braid/height}% + \braid@eh=\pgfkeysvalueof{/pgf/braid/border height}% + \pgfkeysgetvalue{/pgf/braid/control factor}{\braid@cf}% + \pgfkeysgetvalue{/pgf/braid/nudge factor}{\braid@nf}% + \braid@height=-\braid@height + \braid@eh=-\braid@eh + \braid@increase@leveltrue + \braid@process@start +} +% \end{macrocode} +% \end{macro} +% +% These are the lengths we'll use as we construct the braid +% \begin{macrocode} +\newdimen\braid@width +\newdimen\braid@height +\newdimen\braid@tx +\newdimen\braid@ty +\newdimen\braid@nx +\newdimen\braid@ny +\newdimen\braid@cy +\newdimen\braid@dy +\newdimen\braid@eh +% \end{macrocode} +% +% An if to decide whether or not to step to the next level or not +% \begin{macrocode} +\newif\ifbraid@increase@level +% \end{macrocode} +% An if to decide whether label indices should be absolute or not +% \begin{macrocode} +\newif\ifbraid@strand@labels@origin +% \end{macrocode} +% +% +% Some initial values +% \begin{macrocode} +\let\braid@style\pgfutil@empty +\let\braid@floors@style\pgfutil@empty +\def\braid@over@cross{1} +% \end{macrocode} +% +% Counters to track the strands and the levels. +% \begin{macrocode} +\newcounter{braid@level} +\newcounter{braid@strands} +% \end{macrocode} +% +% All the keys we'll use. +% \begin{macrocode} +\pgfkeys{ +% \end{macrocode} +% Handle unknown keys by passing them to \Verb+pgf+ and \Verb+tikz+. +% \begin{macrocode} + /tikz/braid/.search also={/pgf}, + /pgf/braid/.search also={/pgf,/tikz}, +% \end{macrocode} +% Our ``namespace'' is \Verb+/pgf/braid+. +% \begin{macrocode} + /pgf/braid/.cd, + number of strands/.initial=0, + height/.initial=1cm, + width/.initial=1cm, + gap/.initial=.1, + border height/.initial=.25cm, + control factor/.initial=.5, + nudge factor/.initial=.05, + name/.code={% + \def\braid@name{#1}% + }, + at/.code={% + \braid@relocate{#1}% + }, + floor command/.code={% + \def\braid@render@floor{#1}% + }, + style strands/.code 2 args={% + \def\braid@temp{#2}% + \braidset{style each strand/.list={#1}}% + }, + style each strand/.code={% + \expandafter\edef% + \csname braid@options@strand@#1\endcsname{\braid@temp}% + }, + style floors/.code 2 args={% + \def\braid@temp{#2}% + \braidset{style each floor/.list={#1}}% + }, + style each floor/.code={% + \expandafter\edef% + \csname braid@options@floor@#1\endcsname{\braid@temp}% + }, + style all floors/.code={% + \def\braid@floors@style{#1} + }, + strand label/.style={}, + strand label by origin/.is if=braid@strand@labels@origin, +} +% \end{macrocode} +% \begin{macro}{\braidset} +% Shorthand for setting braid-specific keys. +% \begin{macrocode} +\def\braidset#1{% + \pgfkeys{/pgf/braid/.cd,#1}} +% \end{macrocode} +% \end{macro} +% +% \iffalse +%</package> +% \fi +% \begin{macrocode} +%<*library> +%<@@=braid> +% \end{macrocode} +% +% \section{Reimplementation as a TikZ Library} +% +% Life is so much easier with \LaTeX3. +% \begin{macrocode} +\ProvidesFile{tikzlibrarybraids.code.tex}[% + 2019/03/20 v2.0 Tikz/PGF library for drawing braid diagrams% +] +\RequirePackage{expl3} +\ExplSyntaxOn +% \end{macrocode} +% Define all the variables we'll be using. +% \begin{macrocode} +\tl_new:N \l_@@_tmpa_tl +\tl_new:N \l_@@_tmpb_tl +\tl_new:N \l_@@_tmpc_tl +\tl_new:N \l_@@_tmpd_tl +\tl_new:N \l_@@_anchor_strand_tl +\tl_new:N \l_@@_anchor_level_tl +\fp_new:N \l_@@_height_fp +\fp_new:N \l_@@_width_fp +\fp_new:N \l_@@_nudge_fp +\fp_new:N \l_@@_control_fp +\fp_new:N \l_@@_ctrlax_fp +\fp_new:N \l_@@_ctrlay_fp +\fp_new:N \l_@@_ctrlbx_fp +\fp_new:N \l_@@_ctrlby_fp +\fp_new:N \l_@@_endx_fp +\fp_new:N \l_@@_endy_fp +\fp_new:N \l_@@_anchor_x_fp +\fp_new:N \l_@@_anchor_y_fp +\int_new:N \l_@@_tmpa_int +\int_new:N \l_@@_length_int +\int_new:N \l_@@_strands_int +\int_new:N \l_@@_crossing_int +\int_new:N \l_@@_anchor_level_int +\int_new:N \l_@@_floor_int +\seq_new:N \l_@@_word_seq +\seq_new:N \l_@@_crossing_seq +\seq_new:N \l_@@_anchor_seq +\seq_new:N \l_@@_floors_seq +\str_new:N \l_@@_tmpa_str +\str_new:N \l_@@_sup_str +\str_set:Nn \l_@@_sup_str {^} +\str_new:N \l_@@_sub_str +\str_set:Nn \l_@@_sub_str {_} +\str_new:N \l_@@_hyphen_str +\str_set:Nn \l_@@_hyphen_str {-} +\str_new:N \l_@@_bar_str +\str_set:Nn \l_@@_bar_str {|} +\str_new:N \l_@@_one_str +\str_set:Nn \l_@@_one_str {1} +\bool_new:N \l_@@_step_level_bool +\bool_new:N \l_@@_swap_crossing_bool +\bool_new:N \l_@@_floor_bool +\prop_new:N \l_@@_strands_prop +\prop_new:N \l_@@_permutation_prop +\prop_new:N \l_@@_crossing_permutation_prop +\prop_new:N \l_@@_inverse_prop +\prop_new:N \l_@@_anchor_prop +% \end{macrocode} +% Our interface is through a TikZ pic. +% \begin{macrocode} +\tikzset{ + braid/.pic={ + code={ + \@@_parse_word:n {#1} + \@@_count: + \@@_render: + } + }, + floor/.pic={ + code={ + \path[pic~ actions, draw=none] (0,0) rectangle (1,1); + \path[pic~ actions, fill=none] (0,0) -- (1,0) (0,1) -- (1,1); + } + }, + /tikz/braid/.search~ also={/tikz}, + braid/.cd, +% \end{macrocode} +% The various TikZ parameters for the braid. +% +% The anchor determines which part of the braid is located at the position specified by the pic. +% It can be of the form \Verb+n-m+ where \Verb+n+ is a strand number and +m+ is a crossing level. +% The strand number can be either a number or \Verb+rev-n+ to use the ending numbering of the strands. +% The crossing level can also be \Verb+s+ or \Verb+e+ which means the actual start or end of the strand (including the border). +% +% \begin{macrocode} + anchor/.initial=1-s, +% \end{macrocode} +% \Verb+number of strands+ sets a minimum for the number of strands in the braid (otherwise, it is set by the strands used in the specified crossings). +% \begin{macrocode} + number~ of~ strands/.initial=0, +% \end{macrocode} +% \Verb+height+ is the distance between crossings (can be negative). +% \begin{macrocode} + height/.initial=-1cm, +% \end{macrocode} +% \Verb+width+ is the distance between strands (can be negative). +% \begin{macrocode} + width/.initial=1cm, +% \end{macrocode} +% \Verb+gap+ is for determining the gap in the under-strand of a crossing. +% \begin{macrocode} + gap/.initial=.05, +% \end{macrocode} +% \Verb+border height+ is a length added at the start and end of each strand. +% \begin{macrocode} + border~ height/.initial=.25cm, +% \end{macrocode} +% \Verb+floor border+ is added to the width of any floors +% \begin{macrocode} + floor~ border/.initial=.25cm, +% \end{macrocode} +% \Verb+floors+ is a list of floors to draw, specified as a cslist of coordinates as (x,y,w,h,a) in which the units are numbers of strands and crossing levels. +% The parameters are: coordinates of lower left corner, width, height, (optional) name for styling. +% \begin{macrocode} + add~ floor/.code={ + \seq_push:Nn \l_@@_floors_seq {#1} + }, +% \end{macrocode} +% \Verb+control factor+ determines the proportion of the \Verb+height+ used for the control points. +% \begin{macrocode} + control~ factor/.initial=.5, +% \end{macrocode} +% \Verb+nudge factor+ is used to compress each crossing slightly within its rectangle. +% \begin{macrocode} + nudge~ factor/.initial=.05 +} +% \end{macrocode} +% +% \begin{macro}[internal]{\@@_parse_word:Nn} +% Parse the braid word as a token list and convert it into a sequence. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_parse_word:n #1 +{ + \seq_clear:N \l_@@_word_seq + \tl_clear:N \l_@@_tmpa_tl + \tl_set:Nn \l_@@_tmpb_tl {#1} + + \bool_until_do:nn { \tl_if_empty_p:N \l_@@_tmpb_tl } + { +% \end{macrocode} +% We step through the braid specification, looking for special characters. +% To avoid catcode issues, the comparison is as strings. +% Some actions may involve consuming more tokens from the list so we can't do a simple \Verb+map_inline+ but have to keep stripping off the head token. +% +% The idea is to store information about the current crossing in a token list (noting that it may be specified in a variety of orders) and then when we're sure we have all the information we add it to our sequence of crossings. +% \begin{macrocode} + \str_set:Nx \l_@@_tmpa_str {\tl_head:N \l_@@_tmpb_tl} + \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl} +% \end{macrocode} +% +% \begin{macrocode} + \str_case_e:nnTF {\l_@@_tmpa_str} + { +% \end{macrocode} +% Underscore introduces the crossing numbers +% \begin{macrocode} + {_} + { + \tl_put_right:Nx \l_@@_tmpa_tl + { + \exp_not:N \@@_parse_index:n {\tl_head:N \l_@@_tmpb_tl} + } + \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl} + } +% \end{macrocode} +% Power is used to indicate inverse. +% \begin{macrocode} + {^} + { + \tl_put_left:Nx \l_@@_tmpa_tl + { + \exp_not:N \@@_parse_exponent:n {\tl_head:N \l_@@_tmpb_tl} + } + \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl} + } +% \end{macrocode} +% Bar is for floors. +% \begin{macrocode} + {|} + { + \tl_if_empty:NF \l_@@_tmpa_tl + { + \seq_put_right:NV \l_@@_word_seq \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpa_tl + } + + \tl_set:Nn \l_@@_tmpa_tl { + \bool_set_false:N \l_@@_step_level_bool + \bool_set_true:N \l_@@_floor_bool + } + \seq_put_right:NV \l_@@_word_seq \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpa_tl + } +% \end{macrocode} +% Hyphen says the next crossing is on the same level as the current one. +% \begin{macrocode} + {-} + { + \tl_put_right:Nn \l_@@_tmpa_tl + { + \bool_set_false:N \l_@@_step_level_bool + } + } +% \end{macrocode} +% \(1\) is for the identity (i.e., no crossing but still have a level). +% We put a nop token on the list so that it is no longer empty. +% \begin{macrocode} + {1} + { + \tl_if_empty:NF \l_@@_tmpa_tl + { + \seq_put_right:NV \l_@@_word_seq \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpa_tl + } + \tl_put_right:Nn \l_@@_tmpa_tl {\@@_do_identity:} + } +% \end{macrocode} +% Ignore spaces. +% \begin{macrocode} + {~} + { + } + } + { + } + { +% \end{macrocode} +% If we get an unrecognised token, it's our trigger to start accumulating information for the next crossing. +% \begin{macrocode} + \tl_if_empty:NF \l_@@_tmpa_tl + { + \seq_put_right:NV \l_@@_word_seq \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpa_tl + } + } + } +% \end{macrocode} +% At the end, we also put our current token list on the word sequence. +% \begin{macrocode} + \tl_if_empty:NF \l_@@_tmpa_tl + { + \seq_put_right:NV \l_@@_word_seq \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpa_tl + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_parse_index:n} +% Parse an index, saving it in a sequence with the two indices such that the first goes over the second. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_parse_index:n #1 +{ + \seq_set_from_clist:Nn \l_@@_crossing_seq {#1} + \int_compare:nT {\seq_count:N \l_@@_crossing_seq == 1} + { + \seq_put_right:Nx \l_@@_crossing_seq {\int_eval:n {#1 + 1} } + } + \bool_if:NT \l_@@_swap_crossing_bool + { + \seq_pop_left:NN \l_@@_crossing_seq \l_@@_tmpa_tl + \seq_put_right:NV \l_@@_crossing_seq \l_@@_tmpa_tl + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_parse_exponent:n} +% Parse an exponent, basically testing to see if it is \(-1\) in which case our crossing numbers should be reversed.. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_parse_exponent:n #1 +{ + \int_compare:nTF {#1 == -1} + { + \bool_set_true:N \l_@@_swap_crossing_bool + } + { + \bool_set_false:N \l_@@_swap_crossing_bool + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_do_identity:} +% \begin{macrocode} +\cs_new_nopar:Npn \@@_do_identity: +{ +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_count:NNN} +% Work out how big the braid is by counting strands and levels. +% We also figure out the permutation from the start to end of the strands. +% This is useful for labelling various parts of the braid. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_count: +{ + \int_zero:N \l_@@_length_int + \int_set:Nn \l_@@_strands_int {\@@_value:n {number~of~strands}} + \prop_clear:N \l_@@_permutation_prop + \prop_clear:N \l_@@_crossing_permutation_prop + \prop_clear:N \l_@@_anchor_prop + \prop_clear:N \l_@@_inverse_prop + + \seq_map_inline:Nn \l_@@_word_seq + { +% \end{macrocode} +% Clear the crossing sequence and assume we're going to step the level. +% \begin{macrocode} + \seq_clear:N \l_@@_crossing_seq + \bool_set_true:N \l_@@_step_level_bool + \bool_set_false:N \l_@@_swap_crossing_bool +% \end{macrocode} +% Run the details of this crossing. +% \begin{macrocode} + ##1 +% \end{macrocode} +% If we're increasing the level (no hyphen), do so. +% \begin{macrocode} + \bool_if:NT \l_@@_step_level_bool + { + \int_incr:N \l_@@_length_int + } +% \end{macrocode} +% If we have a crossing, check we have enough strands to cover it. +% \begin{macrocode} + \seq_if_empty:NF \l_@@_crossing_seq + { + \int_set:Nn \l_@@_strands_int + { + \int_max:nn + { + \int_max:nn {\l_@@_strands_int} + { \seq_item:Nn \l_@@_crossing_seq {1}} + } + { + \seq_item:Nn \l_@@_crossing_seq {2} + } + } + } + } +% \end{macrocode} +% Now that we know how many strands we have, we can initialise our permutation props. +% One will hold the overall permutation, the other will keep track of our current permutation. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_put:Nnn \l_@@_permutation_prop {##1} {##1} + \prop_put:Nnn \l_@@_anchor_prop {##1} {##1} + \prop_put:Nnn \l_@@_crossing_permutation_prop {##1} {##1} + } +% \end{macrocode} +% Now we step through the braid word again and record the permutations so that we can calculate the overall permutation defined by the braid. +% +% We will also figure out our shift from the anchor, so first we need to get some information about the anchor. +% \begin{macrocode} + \tl_set:Nx \l_@@_tmpa_tl {\@@_value:n {anchor}} + \seq_set_split:NnV \l_@@_anchor_seq {-} \l_@@_tmpa_tl + + \tl_set:Nx \l_@@_tmpa_tl {\seq_item:Nn \l_@@_anchor_seq {1}} + \tl_if_eq:VnTF \l_@@_tmpa_tl {rev} + { + \tl_set:Nx \l_@@_anchor_strand_tl {\seq_item:Nn \l_@@_anchor_seq {2}} + \tl_set:Nx \l_@@_anchor_level_tl {\seq_item:Nn \l_@@_anchor_seq {3}} + } + { + \tl_set:Nx \l_@@_anchor_strand_tl {\seq_item:Nn \l_@@_anchor_seq {1}} + \tl_set:Nx \l_@@_anchor_level_tl {\seq_item:Nn \l_@@_anchor_seq {2}} + } +% \end{macrocode} +% The important information is as to the level at which the requested anchor resides. +% If it is at the end or start of a strand, we set the level to \(-1\) so that it never matches a level number. +% \begin{macrocode} + \tl_if_eq:VnTF \l_@@_anchor_level_tl {s} + { + \int_set:Nn \l_@@_anchor_level_int {-1} + } + { + \tl_if_eq:VnTF \l_@@_anchor_level_tl {e} + { + \int_set:Nn \l_@@_anchor_level_int {-1} + } + { + \int_set:Nn \l_@@_anchor_level_int + {\tl_use:N \l_@@_anchor_level_tl} + } + } + + \int_zero:N \l_@@_crossing_int + \int_incr:N \l_@@_crossing_int +% \end{macrocode} +% +% \begin{macrocode} + \seq_map_inline:Nn \l_@@_word_seq + { + \bool_set_true:N \l_@@_step_level_bool + \seq_clear:N \l_@@_crossing_seq + \bool_set_false:N \l_@@_swap_crossing_bool + ##1 + \seq_if_empty:NF \l_@@_crossing_seq + { + \prop_get:NxN \l_@@_permutation_prop + { + \seq_item:Nn \l_@@_crossing_seq {1} + } \l_@@_tmpa_tl + \prop_get:NxN \l_@@_permutation_prop + { + \seq_item:Nn \l_@@_crossing_seq {2} + } \l_@@_tmpb_tl + + \prop_put:NxV \l_@@_permutation_prop + { + \seq_item:Nn \l_@@_crossing_seq {2} + } \l_@@_tmpa_tl + \prop_put:NxV \l_@@_permutation_prop + { + \seq_item:Nn \l_@@_crossing_seq {1} + } \l_@@_tmpb_tl + } +% \end{macrocode} +% See if the current level is what was requested by the anchor. +% \begin{macrocode} + \int_compare:nT {\l_@@_crossing_int = \l_@@_anchor_level_int} + { + \prop_set_eq:NN \l_@@_anchor_prop \l_@@_permutation_prop + } + \bool_if:NT \l_@@_step_level_bool + { + \int_incr:N \l_@@_crossing_int + } + } +% \end{macrocode} +% This inverts the anchor permutation. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NnN \l_@@_anchor_prop {##1} \l_@@_tmpa_tl + \prop_put:NVn \l_@@_inverse_prop \l_@@_tmpa_tl {##1} + } + \prop_set_eq:NN \l_@@_anchor_prop \l_@@_inverse_prop +% \end{macrocode} +% This inverts the full permutation. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NnN \l_@@_permutation_prop {##1} \l_@@_tmpa_tl + \prop_put:NVn \l_@@_inverse_prop \l_@@_tmpa_tl {##1} + } +% \end{macrocode} +% Now that we have the inverse, we can figure out our anchor. +% First, see if we requested a strand by its position at the end of the braid. +% \begin{macrocode} + \tl_set:Nx \l_@@_tmpa_tl {\seq_item:Nn \l_@@_anchor_seq {1}} + \tl_if_eq:VnT \l_@@_tmpa_tl {rev} + { + \prop_get:NVN \l_@@_permutation_prop + \l_@@_anchor_strand_tl \l_@@_anchor_strand_tl + } + \tl_if_eq:VnF \l_@@_anchor_level_tl {s} + { + \tl_if_eq:VnTF \l_@@_anchor_level_tl {e} + { + \prop_get:NVN \l_@@_inverse_prop + \l_@@_anchor_strand_tl \l_@@_anchor_strand_tl + } + { + \prop_get:NVN \l_@@_anchor_prop + \l_@@_anchor_strand_tl \l_@@_anchor_strand_tl + } + } +% \end{macrocode} +% \begin{macrocode} +} +% \end{macrocode} +% +% +% \end{macro} +% +% +% \begin{macro}{\@@_dim_value:n, \@@_value:n} +% Extract a length or a value from a PGF key. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_dim_value:n #1 +{ + \dim_to_fp:n {\pgfkeysvalueof{/tikz/braid/#1}} +} +\cs_new_nopar:Npn \@@_value:n #1 +{ + \pgfkeysvalueof{/tikz/braid/#1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_render:} +% This is the macro that converts the braid word into TikZ paths. +% \begin{macrocode} +\cs_generate_variant:Nn \prop_get:NnN {NxN} +\cs_generate_variant:Nn \prop_put:Nnn {NxV} +\cs_generate_variant:Nn \tl_if_eq:nnTF {VnTF} +\cs_generate_variant:Nn \tl_if_eq:nnF {VnF} +\cs_generate_variant:Nn \tl_if_eq:nnT {VnT} + +\cs_new_nopar:Npn \@@_render: +{ +% \end{macrocode} +% +% \begin{macrocode} + \fp_set:Nn \l_@@_anchor_x_fp { - 1 * (\tl_use:N \l_@@_anchor_strand_tl - 1) * \@@_dim_value:n {width} } + + \tl_if_eq:VnTF \l_@@_anchor_level_tl {s} + { + \fp_set:Nn \l_@@_anchor_y_fp {0} + } + { + \tl_if_eq:VnTF \l_@@_anchor_level_tl {e} + { + \fp_set:Nn \l_@@_anchor_y_fp { + -1 * \l_@@_length_int * \@@_dim_value:n {height} + - sign(\@@_dim_value:n {height}) + * 2 * \@@_dim_value:n {border~ height} + } + } + { + \fp_set:Nn \l_@@_anchor_y_fp { + -1 * \l_@@_anchor_level_tl * \@@_dim_value:n {height} + - sign(\@@_dim_value:n {height}) + * \@@_dim_value:n {border~ height} + } + } + } + + \begin{scope}[ + shift={ + (\fp_to_decimal:N \l_@@_anchor_x_fp pt, + \fp_to_decimal:N \l_@@_anchor_y_fp pt + ) + } + ] +% \end{macrocode} +% Initialise a prop for the individual strands. +% \begin{macrocode} + \prop_clear:N \l_@@_strands_prop +% \end{macrocode} +% Initialise some lengths. +% \begin{macrocode} + \fp_zero:N \l_@@_height_fp + \fp_zero:N \l_@@_nudge_fp + \fp_zero:N \l_@@_control_fp +% \end{macrocode} +% This holds our current \Verb+height+ of our strands. +% \begin{macrocode} + \fp_set:Nn \l_@@_height_fp + { + sign(\@@_dim_value:n {height}) + * \@@_dim_value:n {border~ height} + } +% \end{macrocode} +% This holds the total \Verb+width+ of our strands. +% \begin{macrocode} + \fp_set:Nn \l_@@_width_fp + { + (\l_@@_strands_int - 1) * \@@_dim_value:n {width} + + 2 * sign(\@@_dim_value:n{width}) + * \@@_dim_value:n {floor~ border} + } +% \end{macrocode} +% Each crossing actually starts a little bit into the crossing space, as defined by the \Verb+nudge factor+. +% \begin{macrocode} + \fp_set:Nn \l_@@_nudge_fp + { + \@@_value:n {nudge~ factor} * \@@_dim_value:n {height} + } +% \end{macrocode} +% This sets where the control points for the crossing curves will be. +% \begin{macrocode} + \fp_set:Nn \l_@@_control_fp + { + \@@_value:n {control~ factor} * \@@_dim_value:n {height} + } + \fp_sub:Nn \l_@@_control_fp {\l_@@_nudge_fp} +% \end{macrocode} +% Initialise our strand paths with a \Verb+\draw+. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NnN \l_@@_inverse_prop {##1} \l_@@_tmpa_tl + \prop_put:Nnx \l_@@_strands_prop {##1} + { + \exp_not:N \draw[ + braid/every~ strand/.try, + braid/strand~ ##1/.try + ] + \exp_not:N \@@_moveto:nn { + \fp_eval:n {(##1 - 1) * \@@_dim_value:n {width} } + } {0} + \exp_not:N \@@_lineto:nn { + \fp_eval:n {(##1 - 1) * \@@_dim_value:n {width} } + } { \fp_to_decimal:N \l_@@_height_fp} + } +% \end{macrocode} +% Add a load of coordinates at the start of each strand, indexed by both forward and backward strand numbers. +% \begin{macrocode} + \@@_coordinate:xxxx {-##1-s} {-rev-\l_@@_tmpa_tl-s} + {\fp_eval:n {(##1 - 1) * \@@_dim_value:n {width} }} {0} + + \@@_coordinate:xxxx {-##1-0} {-rev-\l_@@_tmpa_tl-0} + {\fp_eval:n {(##1 - 1) * \@@_dim_value:n {width} }} + { \fp_to_decimal:N \l_@@_height_fp} + } +% \end{macrocode} +% +% Run through any extra floors requested. +% \begin{macrocode} + \seq_map_inline:Nn \l_@@_floors_seq + { + \tl_set:Nx \l_@@_tmpa_tl {\clist_item:nn {##1} {5}} + \@@_do_floor:Vxxxx \l_@@_tmpa_tl + {\fp_eval:n + { + -1*sign(\@@_dim_value:n{width}) + * \@@_dim_value:n {floor~ border} + + (\@@_dim_value:n {width}) * (\clist_item:nn {##1} {1} - 1) + } + pt + } + {\fp_eval:n + { + \l_@@_height_fp + ( \@@_dim_value:n {height} ) * (\clist_item:nn {##1} {2}) + } + pt + } + {\fp_eval:n { + ( (\clist_item:nn {##1} {3}) * \@@_dim_value:n {width} + + 2 * sign(\@@_dim_value:n{width}) + * \@@_dim_value:n {floor~ border} ) / \dim_to_fp:n {1cm} + } + } + {\fp_eval:n { + (\clist_item:nn {##1} {4}) * ( \@@_dim_value:n {height} ) / \dim_to_fp:n {1cm} + } + } + } +% \end{macrocode} +% +% Keep track of the crossing level for the floor. +% \begin{macrocode} + \int_zero:N \l_@@_crossing_int + \int_incr:N \l_@@_crossing_int + + \seq_map_inline:Nn \l_@@_word_seq + { +% \end{macrocode} +% Clear the flags for this segment of the braid word +% \begin{macrocode} + \seq_clear:N \l_@@_crossing_seq + \bool_set_true:N \l_@@_step_level_bool + \bool_set_false:N \l_@@_floor_bool + \bool_set_false:N \l_@@_swap_crossing_bool + ##1 +% \end{macrocode} +% If we're drawing a floor, do so straightaway. +% \begin{macrocode} + \bool_if:NT \l_@@_floor_bool + { + \@@_do_floor:Vxxxx \l_@@_crossing_int + {\fp_eval:n + { + -1*sign(\@@_dim_value:n{width}) + * \@@_dim_value:n {floor~ border} + } + pt + } + {\fp_to_decimal:N \l_@@_height_fp pt} + {\fp_eval:n { \l_@@_width_fp / \dim_to_fp:n {1cm} }} + {\fp_eval:n { ( \@@_dim_value:n {height} ) / \dim_to_fp:n {1cm}}} + } +% \end{macrocode} +% If we have a crossing, process it. +% \begin{macrocode} + \seq_if_empty:NF \l_@@_crossing_seq + { +% \end{macrocode} +% Keep track of the current permutation. +% \begin{macrocode} + \prop_get:NxN \l_@@_crossing_permutation_prop + {\seq_item:Nn \l_@@_crossing_seq {1}} \l_@@_tmpa_tl + \prop_get:NxN \l_@@_crossing_permutation_prop + {\seq_item:Nn \l_@@_crossing_seq {2}} \l_@@_tmpb_tl + + \prop_put:NxV \l_@@_crossing_permutation_prop + {\seq_item:Nn \l_@@_crossing_seq {2}} \l_@@_tmpa_tl + \prop_put:NxV \l_@@_crossing_permutation_prop + {\seq_item:Nn \l_@@_crossing_seq {1}} \l_@@_tmpb_tl +% \end{macrocode} +% Now get the strands corresponding to the ones involved in the crossing. +% \begin{macrocode} + \prop_get:NxN \l_@@_strands_prop + {\seq_item:Nn \l_@@_crossing_seq {1}} \l_@@_tmpa_tl + \prop_get:NxN \l_@@_strands_prop + {\seq_item:Nn \l_@@_crossing_seq {2}} \l_@@_tmpb_tl +% \end{macrocode} +% The over-strand is easy as that's a single curve. +% \begin{macrocode} + \tl_put_right:Nx \l_@@_tmpa_tl + { + \exp_not:N \@@_lineto:nn + + {\fp_eval:n + { + (\seq_item:Nn \l_@@_crossing_seq {1} - 1) + * \@@_dim_value:n {width} + } + } + {\fp_eval:n { \l_@@_height_fp + \l_@@_nudge_fp } } + + \exp_not:N \@@_curveto:nnnnnn + + {0} + {\fp_eval:n { \l_@@_control_fp}} + + {0} + {\fp_eval:n {- \l_@@_control_fp}} + + {\fp_eval:n + { + (\seq_item:Nn \l_@@_crossing_seq {2} - 1) + * \@@_dim_value:n {width} + } + } + {\fp_eval:n + { + \l_@@_height_fp + + \@@_dim_value:n {height} + - \l_@@_nudge_fp + } + } + } +% \end{macrocode} +% The under-strand is a bit more complicated as we need to break it in the middle. +% \begin{macrocode} + \tl_put_right:Nx \l_@@_tmpb_tl + { + \exp_not:N \@@_lineto:nn + + {\fp_eval:n + { + (\seq_item:Nn \l_@@_crossing_seq {2} - 1) + * \@@_dim_value:n {width} + } + } + {\fp_eval:n { \l_@@_height_fp + \l_@@_nudge_fp } } + + \exp_not:N \@@_curveto:nnnnnn + + {0} + { + \fp_eval:n { + \l_@@_control_fp * (.5 - \@@_value:n {gap} ) + } + } + + { + \fp_eval:n { + - (.5 - \@@_value:n {gap} ) / 3 * + \@@_bezier_tangent:nnnnn + {.5 - \@@_value:n {gap} } + {0} + {0} + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + } + } + { + \fp_eval:n { + -(.5 - \@@_value:n {gap} ) / 3 * + \@@_bezier_tangent:nnnnn + {.5 - \@@_value:n {gap} } + {0} + {\l_@@_control_fp} + { + \@@_dim_value:n {height} + - 2* \l_@@_nudge_fp + - \l_@@_control_fp + } + {\@@_dim_value:n {height} - 2* \l_@@_nudge_fp} + } + } + + { + \fp_eval:n { + (\seq_item:Nn \l_@@_crossing_seq {2} - 1) + * \@@_dim_value:n {width} + + \@@_bezier_point:nnnnn + {.5 - \@@_value:n {gap} } + {0} + {0} + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + } + } + { + \fp_eval:n { + \l_@@_height_fp + \l_@@_nudge_fp + + \@@_bezier_point:nnnnn + {.5 - \@@_value:n {gap} } + {0} + {\l_@@_control_fp} + { + \@@_dim_value:n {height} + - 2* \l_@@_nudge_fp + - \l_@@_control_fp + } + {\@@_dim_value:n {height} - 2* \l_@@_nudge_fp} + } + } + + \exp_not:N \@@_moveto:nn + { + \fp_eval:n { + (\seq_item:Nn \l_@@_crossing_seq {2} - 1) + * \@@_dim_value:n {width} + + \@@_bezier_point:nnnnn + {.5 + \@@_value:n {gap} } + {0} + {0} + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + } + } + { + \fp_eval:n { + \l_@@_height_fp + \l_@@_nudge_fp + + \@@_bezier_point:nnnnn + {.5 + \@@_value:n {gap} } + {0} + {\l_@@_control_fp} + { + \@@_dim_value:n {height} - 2* \l_@@_nudge_fp + - \l_@@_control_fp + } + {\@@_dim_value:n {height} - 2* \l_@@_nudge_fp} + } + } + + \exp_not:N \@@_curveto:nnnnnn + + { + \fp_eval:n { + (.5 - \@@_value:n {gap} ) / 3 * + \@@_bezier_tangent:nnnnn + {.5 + \@@_value:n {gap} } + {0} + {0} + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + { + (\seq_item:Nn \l_@@_crossing_seq {1} + - \seq_item:Nn \l_@@_crossing_seq {2}) + * \@@_dim_value:n {width} + } + } + } + { + \fp_eval:n { + (.5 - \@@_value:n {gap} ) / 3 * + \@@_bezier_tangent:nnnnn + {.5 + \@@_value:n {gap} } + {0} + {\l_@@_control_fp} + { + \@@_dim_value:n {height} - 2* \l_@@_nudge_fp + - \l_@@_control_fp + } + {\@@_dim_value:n {height} - 2* \l_@@_nudge_fp} + } + } + + {0} + { \fp_eval:n { + -\l_@@_control_fp * (.5 - \@@_value:n {gap} ) + } + } + + + {\fp_eval:n + { + (\seq_item:Nn \l_@@_crossing_seq {1} - 1) + * \@@_dim_value:n {width} + } + } + {\fp_eval:n + { + \l_@@_height_fp + \@@_dim_value:n {height} + - \l_@@_nudge_fp + } + } + + } +% \end{macrocode} +% Now put those new strands back in the prop. +% \begin{macrocode} + \prop_put:NxV \l_@@_strands_prop + {\seq_item:Nn \l_@@_crossing_seq {2}} \l_@@_tmpa_tl + \prop_put:NxV \l_@@_strands_prop + {\seq_item:Nn \l_@@_crossing_seq {1}} \l_@@_tmpb_tl +% \end{macrocode} +% If the strands are more than one apart, the intermediate strands need to be broken as well. +% \begin{macrocode} + \int_compare:nT + { + \int_max:nn + { + \seq_item:Nn \l_@@_crossing_seq {1} + } + { + \seq_item:Nn \l_@@_crossing_seq {2} + } + - + \int_min:nn + { + \seq_item:Nn \l_@@_crossing_seq {1} + } + { + \seq_item:Nn \l_@@_crossing_seq {2} + } + > 1 + } + { + \int_step_inline:nnnn + { + \int_min:nn + { + \seq_item:Nn \l_@@_crossing_seq {1} + } + { + \seq_item:Nn \l_@@_crossing_seq {2} + } + + 1} + {1} + { + \int_max:nn + { + \seq_item:Nn \l_@@_crossing_seq {1} + } + { + \seq_item:Nn \l_@@_crossing_seq {2} + } + - 1 + } + { + + \prop_get:NnN \l_@@_strands_prop {####1} \l_@@_tmpa_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + \exp_not:N \@@_lineto:nn + {\fp_eval:n {(####1 - 1) * \@@_dim_value:n {width} }} + {\fp_eval:n + { + \l_@@_height_fp + \l_@@_nudge_fp + + .5 * \l_@@_control_fp + } + } + \exp_not:N \@@_moveto:nn + {\fp_eval:n {(####1 - 1) * \@@_dim_value:n {width} }} + {\fp_eval:n + { + \l_@@_height_fp + \@@_dim_value:n {height} + - \l_@@_nudge_fp - .5 * \l_@@_control_fp + } + } + } + + \prop_put:NnV \l_@@_strands_prop {####1} \l_@@_tmpa_tl + } + } + } +% \end{macrocode} +% If we're to step the level, increase the height and add a load of coordinates. +% \begin{macrocode} + \bool_if:NT \l_@@_step_level_bool + { + \fp_add:Nn \l_@@_height_fp { \@@_dim_value:n {height} } + + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NnN \l_@@_crossing_permutation_prop + {####1} \l_@@_tmpb_tl + \prop_get:NVN \l_@@_inverse_prop + \l_@@_tmpb_tl \l_@@_tmpa_tl + + \@@_coordinate:xxxx + {-\l_@@_tmpb_tl-\int_use:N \l_@@_crossing_int} + {-rev-\l_@@_tmpa_tl-\int_use:N \l_@@_crossing_int } + {\fp_eval:n { (####1 - 1) * \@@_dim_value:n {width} }} + {\fp_to_decimal:N \l_@@_height_fp} + } + + \int_incr:N \l_@@_crossing_int + } + } + + \fp_add:Nn \l_@@_height_fp + { + sign(\@@_dim_value:n {height}) + * \@@_dim_value:n {border~ height} + } +% \end{macrocode} +% Add a little bit to the end of each strand, together with some coordinates. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NxN \l_@@_strands_prop {##1} \l_@@_tmpa_tl + \prop_get:NxN \l_@@_permutation_prop {##1} \l_@@_tmpb_tl + + \tl_put_right:Nx \l_@@_tmpa_tl { + \exp_not:N \@@_lineto:nn + {\fp_eval:n { (##1 - 1) * \@@_dim_value:n {width} }} + {\fp_to_decimal:N \l_@@_height_fp} + coordinate (-rev-##1-e) + coordinate (-\l_@@_tmpb_tl-e) + ; + } + + \prop_put:NnV \l_@@_strands_prop {##1} \l_@@_tmpa_tl + } +% \end{macrocode} +% This is where we actually carry out the drawing commands. +% \begin{macrocode} + \int_step_inline:nnnn {1} {1} {\l_@@_strands_int} + { + \prop_get:NnN \l_@@_strands_prop {##1} \l_@@_tmpa_tl + \tl_use:N \l_@@_tmpa_tl + } + \end{scope} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_moveto:nn, \@@_lineto:nn, \@@_curveto:nnnnnn, \@@_coordinate:nnnn} +% These are our interfaces to the TikZ code. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_moveto:nn #1#2 +{ + (#1 pt, #2 pt) +} +\cs_new_nopar:Npn \@@_lineto:nn #1#2 +{ + -- (#1 pt, #2 pt) +} +\cs_new_nopar:Npn \@@_curveto:nnnnnn #1#2#3#4#5#6 +{ + .. controls +(#1 pt, #2 pt) and +(#3 pt, #4 pt) + .. (#5 pt, #6 pt) +} +\cs_new_nopar:Npn \@@_coordinate:nnnn #1#2#3#4 +{ + \coordinate[alias=#2] (#1) at (#3 pt,#4 pt); +} +\cs_generate_variant:Nn \@@_coordinate:nnnn {xxxx} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\@@_bezier_point:nnnnn, \@@_bezier_tangent:nnnnn} +% Used to calculate intermediate points and tangents on a bezier curve. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_bezier_point:nnnnn #1#2#3#4#5 +{ + \fp_eval:n + { + (1 - (#1)) * (1 - (#1)) * (1 - (#1)) * (#2) + + + 3 * (1 - (#1)) * (1 - (#1)) * (#1) * (#3) + + + 3 * (1 - (#1)) * (#1) * (#1) * (#4) + + + (#1) * (#1) * (#1) * (#5) + } +} +\cs_new_nopar:Npn \@@_bezier_tangent:nnnnn #1#2#3#4#5 +{ + \fp_eval:n + { + 3 * (1 - (#1)) * (1 - (#1)) * (#3 - (#2)) + + + 6 * (1 - (#1)) * (#1) * (#4 - (#3)) + + + 3 * (#1) * (#1) * (#5 - (#4)) + } +} +\cs_new_nopar:Npn \@@_do_floor:nnnnn #1#2#3#4#5 +{ + \pic[pic~ type=floor, + xscale=#4, + yscale=#5, + at={(#2,#3)}, + braid/every~ floor/.try, + braid/floor~#1/.try, + ]; +} +\cs_generate_variant:Nn \@@_do_floor:nnnnn {Vxxxx} +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \iffalse +%</library> +% \fi +% +% \Finale + +\endinput diff --git a/graphics/pgf/contrib/braids/braids_code.pdf b/graphics/pgf/contrib/braids/braids_code.pdf Binary files differnew file mode 100644 index 0000000000..d60b9b6f39 --- /dev/null +++ b/graphics/pgf/contrib/braids/braids_code.pdf |