summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/braids/braids_code.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/braids/braids_code.dtx')
-rw-r--r--Master/texmf-dist/source/latex/braids/braids_code.dtx2321
1 files changed, 2321 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/braids/braids_code.dtx b/Master/texmf-dist/source/latex/braids/braids_code.dtx
new file mode 100644
index 00000000000..51a4ee2c600
--- /dev/null
+++ b/Master/texmf-dist/source/latex/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