summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/spath3
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-04-13 22:58:30 +0000
committerKarl Berry <karl@freefriends.org>2013-04-13 22:58:30 +0000
commit2990bdaecab058888c965905ed0bd12587a292aa (patch)
tree25198bedccfa37fe48865a1bdcc03bd4f7de8cc9 /Master/texmf-dist/source/latex/spath3
parent5cc36a171f8092e44ab898ee2e44446b5c4a2949 (diff)
spath3 (12apr13)
git-svn-id: svn://tug.org/texlive/trunk@29898 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/spath3')
-rw-r--r--Master/texmf-dist/source/latex/spath3/spath3.dtx3836
-rw-r--r--Master/texmf-dist/source/latex/spath3/spath3.ins91
2 files changed, 3927 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/spath3/spath3.dtx b/Master/texmf-dist/source/latex/spath3/spath3.dtx
new file mode 100644
index 00000000000..4febfd505f1
--- /dev/null
+++ b/Master/texmf-dist/source/latex/spath3/spath3.dtx
@@ -0,0 +1,3836 @@
+% \iffalse meta-comment
+%<*internal>
+\iffalse
+%</internal>
+%<*readme>
+----------------------------------------------------------------
+spath3 --- LaTeX3 functions for manipulating PGF soft paths
+E-mail: stacey@math.ntnu.no
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+----------------------------------------------------------------
+
+This package defines some functions used to manipulate PGFs soft paths.
+As applications of its use, included are a package for drawing calligraphic paths and a package for drawing knot diagrams.
+%</readme>
+%<*internal>
+\fi
+\def\nameofplainTeX{plain}
+\ifx\fmtname\nameofplainTeX\else
+ \expandafter\begingroup
+\fi
+%</internal>
+%<*install>
+\input docstrip.tex
+\keepsilent
+\askforoverwritefalse
+\preamble
+----------------------------------------------------------------
+spath3 --- Functions for manipulating PGF soft paths
+E-mail: stacey@math.ntnu.no
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+----------------------------------------------------------------
+
+\endpreamble
+\postamble
+
+Copyright (C) 2011 by Andrew Stacey <stacey@math.ntnu.no>
+
+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 spath3.dtx
+ calligraphy_doc.tex
+ knot_doc.tex
+and the derived files spath3.ins,
+ spath3.pdf,
+ spath3.sty,
+ tikzlibrarycalligraphy.code.tex
+ tikzlibraryknots.code.tex
+ calligraphy_doc.pdf
+ knots_doc.pdf
+ README.txt
+
+\endpostamble
+\usedir{tex/latex/spath3}
+\generate{
+ \file{\jobname.sty}{\from{\jobname.dtx}{spath3}}
+}
+\generate{
+ \file{tikzlibrarycalligraphy.code.tex}{\from{\jobname.dtx}{calligraphy}}
+}
+\generate{
+ \file{tikzlibraryknots.code.tex}{\from{\jobname.dtx}{knots}}
+}
+%</install>
+%<install>\endbatchfile
+%<*internal>
+\usedir{source/latex/spath3}
+\generate{
+ \file{\jobname.ins}{\from{\jobname.dtx}{install}}
+}
+\nopreamble\nopostamble
+\usedir{doc/latex/demopkg}
+\generate{
+ \file{README.txt}{\from{\jobname.dtx}{readme}}
+}
+\ifx\fmtname\nameofplainTeX
+ \expandafter\endbatchfile
+\else
+ \expandafter\endgroup
+\fi
+%</internal>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage[T1]{fontenc}
+\usepackage{lmodern}
+%\usepackage{morefloats}
+\usepackage{tikz}
+\usepackage{trace}
+\usepackage{spath3}
+%\traceoff
+%\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}[gobble=2]{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}
+}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{4024}
+%
+% \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}
+%
+% \DoNotIndex{\newcommand,\newenvironment}
+%
+% \providecommand*{\url}{\texttt}
+% \GetFileInfo{spath3.sty}
+% \title{The \textsf{spath3} package}
+% \author{Andrew Stacey \\ \url{stacey@math.ntnu.no}}
+% \date{\fileversion~from \filedate}
+%
+%
+% \maketitle
+%
+%
+% \section{Introduction}
+%
+% The \Verb+spath3+ package is intended as a library for manipulating PGF's \emph{soft paths}.
+% In between defining a path and using it, PGF stores a path as a \emph{soft path} were all the defining structure has been resolved into the basic operations but these have not yet been written to the output file.
+% They can therefore still be manipulated by \TeX, and as they have a very rigid form (and limited vocabulary), they are relatively easy to modify.
+% This package provides some methods for working with these paths.
+% It is not really intended for use by end users but as a foundation on which other packages can be built.
+% As examples, the \Verb+calligraphy+ package and the \Verb+knot+ package are included.
+% The first of these simulates a calligraphic pen stroking a path.
+% The second can be used to draw knot (and similar) diagrams.
+%
+% The format of a soft path is a sequence of triples of the form \Verb+\macro {dimension}{dimension}+.
+% The macro is one of a short list, the dimensions are coordinates in points.
+% There are certain further restrictions, particularly that every path must begin with a \Verb+move to+, and B\'ezier curves consist of three triples.
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+%
+% \iffalse
+%<*spath3>
+% \fi
+% \subsection{Initialisation}
+%
+% Load the \LaTeX3 foundation and register us as a \LaTeX3\ package.
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}
+\RequirePackage{expl3}
+\RequirePackage{pgf}
+\ProvidesExplPackage {spath3} {2013/04/09} {1.0} {Functions for
+manipulating PGF soft paths}
+\RequirePackage{xparse}
+% \end{macrocode}
+%
+% We need a slew of temporary variables.
+% \begin{macrocode}
+\tl_new:N \l__spath_tmpa_tl
+\tl_new:N \l__spath_tmpb_tl
+\tl_new:N \l__spath_tmpc_tl
+\tl_new:N \l__spath_tmpd_tl
+\tl_new:N \l__spath_smuggle_tl
+\dim_new:N \l__spath_tmpa_dim
+\dim_new:N \l__spath_tmpb_dim
+\int_new:N \l__spath_tmpa_int
+% \end{macrocode}
+%
+% We need to be able to compare against the macros that can occur in a soft path so these token lists contain them.
+% \begin{macrocode}
+\tl_new:N \g__spath_moveto_tl
+\tl_new:N \g__spath_lineto_tl
+\tl_new:N \g__spath_curveto_tl
+\tl_new:N \g__spath_curvetoa_tl
+\tl_new:N \g__spath_curvetob_tl
+\tl_set:Nn \g__spath_moveto_tl {\pgfsyssoftpath@movetotoken}
+\tl_set:Nn \g__spath_lineto_tl {\pgfsyssoftpath@linetotoken}
+\tl_set:Nn \g__spath_curveto_tl {\pgfsyssoftpath@curvetotoken}
+\tl_set:Nn \g__spath_curvetoa_tl {\pgfsyssoftpath@curvetosupportatoken}
+\tl_set:Nn \g__spath_curvetob_tl {\pgfsyssoftpath@curvetosupportbtoken}
+% \end{macrocode}
+%
+% \subsection{Basic Structure and Methods}
+%
+% A soft path is a \Verb+prop+.
+% These are lists of the attributes that we define.
+% The first consists of all attributes, the second of those that are ``moveable'' in the sense that they change if we transform the path, the third are the ones that contain actual paths.
+%
+% Note that if using these attributes outside an \Verb+expl3+ context, the spaces should be omitted.
+% \begin{macrocode}
+\tl_new:N \g__spath_attributes
+\tl_new:N \g__spath_moveable_attributes
+\tl_new:N \g__spath_path_attributes
+\tl_set:Nn \g__spath_attributes {
+ {path}
+ {reverse path}
+ {length}
+ {real length}
+ {number of components}
+ {initial point}
+ {final point}
+ {initial action}
+ {final action}
+ {min bb}
+ {max bb}
+}
+\tl_set:Nn \g__spath_moveable_attributes {
+ {initial point}
+ {final point}
+ {min bb}
+ {max bb}
+}
+\tl_set:Nn \g__spath_path_attributes {
+ {path}
+ {reverse path}
+}
+% \end{macrocode}
+%
+% An \Verb+spath+ object is actually a \Verb+prop+.
+% The following functions are wrappers around the underlying \Verb+prop+ functions.
+% We prefix the names to avoid clashing with other \Verb+prop+s that might be lying around, this is why all the \Verb+spath+ methods take argument \Verb+:n+ and not \Verb+:N+.
+% Given that \Verb+spath+ objects might be created inside a group but used outside it, we work globally throughout.
+% \begin{macro}{\spath_new:n}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_new:n #1
+{
+ \prop_new:c {l__spath_#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_clear:n}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_clear:n #1
+{
+ \prop_gclear:c {l__spath_#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_clear_new:n}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_clear_new:n #1
+{
+ \prop_gclear_new:c {l__spath_#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_show:n}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_show:n #1
+{
+ \prop_show:c {l__spath_#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_put:nnn}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_put:nnn #1#2#3
+{
+ \prop_gput:cnn {l__spath_#1} {#2} {#3}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_remove:nn}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_remove:nn #1#2
+{
+ \prop_gremove:cn {l__spath_#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__spath_get:nn}
+% This function is an internal one since the real \Verb+get+ function will generate its data if it does not already exist.
+% \begin{macrocode}
+\cs_new_nopar:Npn \__spath_get:nn #1#2
+{
+ \prop_get:cn {l__spath_#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__spath_get:nnN}
+% \begin{macrocode}
+\cs_new_nopar:Npn \__spath_get:nnN #1#2#3
+{
+ \prop_get:cnN {l__spath_#1} {#2} #3
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_if_in:nn}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \spath_if_in:nn #1#2 {p, T, F, TF}
+{
+ \prop_if_in:cnTF {l__spath_#1} {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\_spath_get:nnN}
+% \begin{macrocode}
+\cs_generate_variant:Nn \__prop_split:NnTF {cnTF}
+\prg_new_protected_conditional:Npnn \__spath_get:nnN #1#2#3 {T, F, TF}
+{
+ \__prop_split:cnTF {l__spath_#1} {#2}
+ { \__prop_get_true:Nnnn #3 }
+ { \prg_return_false: }
+}
+\cs_generate_variant:Nn \spath_put:nnn {nnV, nnx, nno}
+\cs_generate_variant:Nn \__spath_get:nn {Vn}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_if_exist:n}
+% \begin{macrocode}
+\prg_new_conditional:Npnn \spath_if_exist:n #1 {p,T,F,TF}
+{
+ \prop_if_exist:cTF {l__spath_#1}
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_clone:nn}
+% Clones an \Verb+spath+.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_clone:nn #1 #2
+{
+ \spath_clear_new:n {#2}
+ \tl_map_inline:Nn \g__spath_attributes
+ {
+ \spath_if_in:nnT {#1} {##1}
+ {
+ \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl
+ \spath_put:nnV {#2} {##1} \l__spath_tmpa_tl
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_get_current_path:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_get_current_path:n #1
+{
+ \pgfsyssoftpath@getcurrentpath\l__knot_tmpa_tl
+ \spath_clear_new:n {#1}
+ \spath_put:nnV {#1} {path} \l__knot_tmpa_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_set_current_path:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_set_current_path:n #1
+{
+ \spath_get:nnN {#1} {min bb} \l__spath_tmpa_tl
+ \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl
+
+ \spath_get:nnN {#1} {max bb} \l__spath_tmpa_tl
+ \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl
+
+ \spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \pgfsyssoftpath@setcurrentpath\l__spath_tmpa_tl
+ \pgfsyssoftpath@flushcurrentpath
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_use_path:nn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_use_path:nn #1#2
+{
+ \spath_set_current_path:n {#1}
+ \pgfusepath{#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_protocol_path:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_protocol_path:n #1
+{
+ \spath_get:nnN {#1} {min bb} \l__spath_tmpa_tl
+ \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl
+
+ \spath_get:nnN {#1} {max bb} \l__spath_tmpa_tl
+ \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_tikz_path:nn}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2
+{
+ \path[#1] \pgfextra{
+ \spath_get:nnN {#2} {path} \l__spath_tmpa_tl
+ \pgfsyssoftpath@setcurrentpath \l__spath_tmpa_tl
+ };
+}
+\cs_generate_variant:Nn \spath_tikz_path:nn {Vn}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Computing Information}
+%
+% \begin{macro}{\spath_get:nn}
+% The information that we store along with a soft path can be computed from it, but computing it every time is wasteful.
+% So this is the real \Verb+\spath_get:nn+ function which checks to see if we have already computed it and then either retrieves it or computes it.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_get:nn #1#2
+{
+ \spath_if_in:nnF {#1} {#2}
+ {
+ \cs_if_exist_use:cT {spath_generate_#2:n} {{#1}}
+ }
+ \__spath_get:nn {#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_get:nnN}
+% As above but leaves the result in a token list rather than in the stream.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_get:nnN #1#2#3
+{
+ \spath_if_in:nnF {#1} {#2}
+ {
+ \cs_if_exist_use:cT {spath_generate_#2:n} {{#1}}
+ }
+ \__spath_get:nnN {#1} {#2} #3
+}
+\cs_generate_variant:Nn \spath_get:nnN {nnV}
+% \end{macrocode}
+% \end{macro}
+%
+% The next slew of functions generate data from the original path, storing it in the \Verb+prop+ for further retrieval.
+% \begin{macro}{\spath_generate_length:n}
+% Counts the number of triples in the path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_length:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \spath_put:nnx {#1} {length} {\int_eval:n {\tl_count:N \l__spath_tmpa_tl /3 }}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_reallength:n}
+% The real length of a path is the number of triples that actually draw something (that is, the number of lines and curves).
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_reallength:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \int_set:Nn \l__spath_tmpa_int {0}
+ \tl_map_inline:Nn \l__spath_tmpa_tl {
+ \tl_if_eq:nnT {##1} {\pgfsyssoftpath@linetotoken}
+ {
+ \int_incr:N \l__spath_tmpa_int
+ }
+ \tl_if_eq:nnT {##1} {\pgfsyssoftpath@curvetotoken}
+ {
+ \int_incr:N \l__spath_tmpa_int
+ }
+ }
+ \spath_put:nnx {#1} {real length} {\int_use:N \l__spath_tmpa_int}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_numberofcomponents:n}
+% A component is a continuous segment of the path, separated by moves.
+% Successive moves are not collapsed, and zero length moves count.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_numberofcomponents:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \int_set:Nn \l__spath_tmpa_int {0}
+ \tl_map_inline:Nn \l__spath_tmpa_tl {
+ \tl_if_eq:nnT {##1} {\pgfsyssoftpath@movetotoken}
+ {
+ \int_incr:N \l__spath_tmpa_int
+ }
+ }
+ \spath_put:nnx {#1} {number of components} {\int_use:N \l__spath_tmpa_int}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_initialpoint:n}
+% The starting point of the path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_initialpoint:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \spath_put:nnV {#1} {initial point} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_finalpoint:n}
+% The final point of the path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_finalpoint:n #1
+{
+ \tl_clear:N \l__spath_tmpb_tl
+ \spath_if_in:nnTF {#1} {reverse path}
+ {
+ \__spath_get:nnN {#1} {reverse path} \l__spath_tmpa_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ }
+ {
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_reverse:N \l__spath_tmpa_tl
+ \tl_put_left:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_left:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ }
+ \spath_put:nnV {#1} {final point} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_reversepath:n}
+% This computes the reverse of the path.
+% TODO: handle closed paths, possibly rectangles.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_reversepath:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_left:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nn \l__spath_tmpd_tl {}
+ \tl_case:Nnn \l__spath_tmpc_tl
+ {
+ \g__spath_moveto_tl {\tl_set_eq:NN \l__spath_tmpd_tl \g__spath_moveto_tl }
+ \g__spath_lineto_tl {\tl_set_eq:NN \l__spath_tmpd_tl \g__spath_lineto_tl }
+ \g__spath_curveto_tl {\tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curvetoa_tl }
+ \g__spath_curvetoa_tl {\tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curveto_tl }
+ \g__spath_curvetob_tl {\tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curvetob_tl }
+ }
+ {
+ \tl_show:N \l__spath_tmpc_tl
+ }
+ \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_left:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ \tl_put_left:NV \l__spath_tmpb_tl \g__spath_moveto_tl
+ \spath_put:nnV {#1} {reverse path} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_initialaction:n}
+% This is the first thing that the path does (after the initial move).
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_initialaction:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_if_empty:NF \l__spath_tmpa_tl {
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+ }
+ \spath_put:nnV {#1} {initial action} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_final action:n}
+% This is the last thing that the path does.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_finalaction:n #1
+{
+ \tl_clear:N \l__spath_tmpb_tl
+ \spath_if_in:nnTF {#1} {reverse path}
+ {
+ \__spath_get:nnN {#1} {reverse path} \l__spath_tmpa_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ }
+ {
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_reverse:N \l__spath_tmpa_tl
+ }
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_if_empty:NF \l__spath_tmpa_tl {
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+ }
+ \tl_if_eq:NNT \l__spath_tmpa_tl \g__spath_curvetoa_tl
+ {
+ \tl_set_eq:NN \l__spath_tmpa_tl \g__spath_curveto_tl
+ }
+ \spath_put:nnV {#1} {final action} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_minbb:n}
+% This computes the minimum (bottom left) of the bounding box of the path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_minbb:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ }
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {min bb} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_max bb:n}
+% This computes the maximum (top right) of the bounding box of the path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_generate_maxbb:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ }
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {max bb} \l__spath_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_generate_all:n}
+% This function generates all of the data in one fell swoop.
+% By traversing the path just once it is quicker than doing each one individually.
+% However, it does need to store a lot of data as it goes.
+% \begin{itemize}
+% \item \Verb+\l__spath_rp_tl+ will hold the reversed path
+% \item \Verb+\l__spath_l_int+ will hold the length
+% \item \Verb+\l__spath_rl_int+ will hold the real length
+% \item \Verb+\l__spath_nc_int+ will hold the number of components
+% \item \Verb+\l__spath_ip_tl+ will hold the initial point
+% \item \Verb+\l__spath_fp_tl+ will hold the final point
+% \item \Verb+\l__spath_ia_tl+ will hold the initial action
+% \item \Verb+\l__spath_fa_tl+ will hold the final action
+% \item \Verb+\l__spath_minx_dim+ will hold the min x bb
+% \item \Verb+\l__spath_miny_dim+ will hold the min y bb
+% \item \Verb+\l__spath_maxx_dim+ will hold the max x bb
+% \item \Verb+\l__spath_maxy_dim+ will hold the max y bb
+% \end{itemize}
+% \begin{macrocode}
+\tl_new:N \l__spath_rp_tl
+\int_new:N \l__spath_l_int
+\int_new:N \l__spath_rl_int
+\int_new:N \l__spath_nc_int
+\tl_new:N \l__spath_ip_tl
+\tl_new:N \l__spath_fp_tl
+\tl_new:N \l__spath_ia_tl
+\tl_new:N \l__spath_fa_tl
+\dim_new:N \l__spath_minx_dim
+\dim_new:N \l__spath_miny_dim
+\dim_new:N \l__spath_maxx_dim
+\dim_new:N \l__spath_maxy_dim
+
+\cs_new_nopar:Npn \spath_generate_all:n #1
+{
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+
+ \tl_clear:N \l__spath_rp_tl
+ \int_set:Nn \l__spath_l_int {1}
+ \int_zero:N \l__spath_rl_int
+ \int_set:Nn \l__spath_nc_int {1}
+ \tl_clear:N \l__spath_ip_tl
+ \tl_clear:N \l__spath_fp_tl
+ \tl_clear:N \l__spath_ia_tl
+ \tl_clear:N \l__spath_fa_tl
+ \dim_zero:N \l__spath_minx_dim
+ \dim_zero:N \l__spath_miny_dim
+ \dim_zero:N \l__spath_maxx_dim
+ \dim_zero:N \l__spath_maxy_dim
+
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_clear:N \l__spath_ip_tl
+ \tl_put_right:Nx \l__spath_ip_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+
+ \dim_set_eq:NN \l__spath_minx_dim \l__spath_tmpa_dim
+ \dim_set_eq:NN \l__spath_miny_dim \l__spath_tmpb_dim
+ \dim_set_eq:NN \l__spath_maxx_dim \l__spath_tmpa_dim
+ \dim_set_eq:NN \l__spath_maxy_dim \l__spath_tmpb_dim
+
+ \tl_put_left:Nx \l__spath_rp_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+
+ \tl_set:Nx \l__spath_ia_tl {\tl_head:N \l__spath_tmpa_tl}
+
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nn \l__spath_tmpd_tl {}
+ \tl_set_eq:NN \l__spath_fa_tl \l__spath_tmpc_tl
+ \int_incr:N \l__spath_l_int
+
+ \tl_case:Nnn \l__spath_tmpc_tl
+ {
+ \g__spath_moveto_tl {
+ \tl_set_eq:NN \l__spath_tmpd_tl \g__spath_moveto_tl
+ \int_incr:N \l__spath_nc_int
+ }
+ \g__spath_lineto_tl {
+ \tl_set_eq:NN \l__spath_tmpd_tl \g__spath_lineto_tl
+ \int_incr:N \l__spath_rl_int
+ }
+ \g__spath_curveto_tl {
+ \tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curvetoa_tl
+ \int_incr:N \l__spath_rl_int
+ }
+ \g__spath_curvetoa_tl {
+ \tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curveto_tl
+ }
+ \g__spath_curvetob_tl {
+ \tl_set_eq:NN \l__spath_tmpd_tl \g__spath_curvetob_tl
+ }
+ }
+ {
+ \tl_show:N \l__spath_tmpc_tl
+ }
+ \tl_put_left:NV \l__spath_rp_tl \l__spath_tmpd_tl
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_minx_dim {\dim_min:nn { \l__spath_minx_dim} {\l__spath_tmpa_dim}}
+ \dim_set:Nn \l__spath_miny_dim {\dim_min:nn { \l__spath_miny_dim} {\l__spath_tmpb_dim}}
+ \dim_set:Nn \l__spath_maxx_dim {\dim_max:nn { \l__spath_maxx_dim} {\l__spath_tmpa_dim}}
+ \dim_set:Nn \l__spath_maxy_dim {\dim_max:nn { \l__spath_maxy_dim} {\l__spath_tmpb_dim}}
+
+ \tl_put_left:Nx \l__spath_rp_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+
+ \tl_set:Nx \l__spath_fp_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+
+ }
+
+ \tl_put_left:NV \l__spath_rp_tl \g__spath_moveto_tl
+
+ \spath_put:nnV {#1} {reverse path} \l__spath_rp_tl
+ \spath_put:nnV {#1} {length} \l__spath_l_int
+ \spath_put:nnV {#1} {real length} \l__spath_rl_int
+ \spath_put:nnV {#1} {number of components} \l__spath_nc_int
+ \spath_put:nnV {#1} {initial point} \l__spath_ip_tl
+ \spath_put:nnV {#1} {final point} \l__spath_fp_tl
+ \spath_put:nnV {#1} {initial action} \l__spath_ia_tl
+ \spath_put:nnV {#1} {final action} \l__spath_fa_tl
+
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_minx_dim}
+ {\dim_use:N \l__spath_miny_dim}
+ }
+ \spath_put:nnV {#1} {min bb} \l__spath_tmpb_tl
+
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_maxx_dim}
+ {\dim_use:N \l__spath_maxy_dim}
+ }
+ \spath_put:nnV {#1} {max bb} \l__spath_tmpb_tl
+
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Path Manipulation}
+%
+% \begin{macro}{\spath_translate:nnn}
+% Translates a path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_translate:nnn #1#2#3
+{
+ \tl_map_inline:Nn \g__spath_moveable_attributes
+ {
+ \spath_if_in:nnT {#1} {##1}
+ {
+ \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl + #2}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl + #3}
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl
+ }
+ }
+ \tl_map_inline:Nn \g__spath_path_attributes
+ {
+ \spath_if_in:nnT {#1} {##1}
+ {
+ \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl
+ \tl_clear:N \l__spath_tmpb_tl
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl + #2}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl + #3}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl
+ }
+ }
+}
+
+\cs_generate_variant:Nn \spath_translate:nnn {nxx}
+% \end{macrocode}
+%
+% This variant allows for passing the coordinates as a single braced group as it strips off the outer braces of the second argument.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_translate:nn #1#2
+{
+ \spath_translate:nnn {#1} #2
+}
+
+\cs_generate_variant:Nn \spath_translate:nn {nV}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_scale:nnn}
+% Scale a path.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_scale:nnn #1#2#3
+{
+ \tl_map_inline:Nn \g__spath_moveable_attributes
+ {
+ \spath_if_in:nnT {#1} {##1}
+ {
+ \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl * #2}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl * #3}
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl
+ }
+ }
+ \tl_map_inline:Nn \g__spath_path_attributes
+ {
+ \spath_if_in:nnT {#1} {##1}
+ {
+ \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl
+ \tl_clear:N \l__spath_tmpb_tl
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl * #2}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl * #3}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_reverse:n}
+% This reverses a path.
+% As a lot of the data is invariant under reversing, there isn't a lot to do.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_reverse:n #1
+{
+ \spath_if_in:nnF {#1} {reverse path} {
+ \cs_use:c {spath_generate_reverse path}
+ }
+ \spath_swap:nnn {#1} {path} {reverse path}
+ \spath_swap:nnn {#1} {initial point} {final point}
+ \spath_swap:nnn {#1} {initial action} {final action}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_swap:nnn}
+% Swaps two entries, being careful to ensure that their existence (or otherwise) is preserved.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_swap:nnn #1#2#3
+{
+ \__spath_get:nnNF {#1} {#2} \l__spath_tmpa_tl {\tl_clear:N \l__spath_tmpa_tl}
+ \__spath_get:nnNF {#1} {#3} \l__spath_tmpb_tl {\tl_clear:N \l__spath_tmpb_tl}
+ \tl_if_empty:NTF \l__spath_tmpb_tl
+ {\spath_remove:nnV {#1} {#2}}
+ {\spath_put:nnV {#1} {#2} \l__spath_tmpb_tl}
+ \tl_if_empty:NTF \l__spath_tmpa_tl
+ {\spath_remove:nnV {#1} {#3}}
+ {\spath_put:nnV {#1} {#3} \l__spath_tmpa_tl}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_weld:nn}
+% This welds one path to another, moving the second so that it's initial point coincides with the first's final point.
+% It is called a \emph{weld} because the initial move of the second path is removed.
+% The first path is updated, the second is not modified.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_weld:nn #1#2
+{
+ \spath_clone:nn {#2} {tmp_path}
+ \spath_get:nnN {#1} {final point} \l__spath_tmpa_tl
+
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+
+ \spath_get:nnN {#2} {initial point} \l__spath_tmpa_tl
+
+ \dim_sub:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_sub:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+
+ \spath_translate:nxx {tmp_path} {\dim_use:N \l__spath_tmpa_dim} {\dim_use:N \l__spath_tmpb_dim}
+
+ \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \__spath_get:nnN {tmp_path} {path} \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+
+ \spath_put:nnV {#1} {path} \l__spath_tmpa_tl
+
+ \__spath_get:nnNTF {tmp_path} {final point} \l__spath_tmpa_tl
+ {
+ \spath_put:nnV {#1} {final point} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {final point}
+ }
+
+ \__spath_get:nnNTF {tmp_path} {final action} \l__spath_tmpa_tl
+ {
+ \spath_put:nnV {#1} {final action} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {final action}
+ }
+
+ \__spath_get:nnNT {tmp_path} {min bb} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {min bb} \l__spath_tmpb_tl
+ {
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\l__spath_tmpa_dim} {\tl_head:N \l__spath_tmpb_tl}}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\l__spath_tmpb_dim} {\tl_head:N \l__spath_tmpb_tl}}
+
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {min bb} \l__spath_tmpb_tl
+ }
+ }
+
+ \__spath_get:nnNT {tmp_path} {max bb} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {max bb} \l__spath_tmpb_tl
+ {
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_max:nn {\l__spath_tmpa_dim} {\tl_head:N \l__spath_tmpb_tl}}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_max:nn {\l__spath_tmpb_dim} {\tl_head:N \l__spath_tmpb_tl}}
+
+ \tl_clear:N \l__spath_tmpb_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \spath_put:nnV {#1} {max bb} \l__spath_tmpb_tl
+ }
+ }
+
+ \__spath_get:nnNT {tmp_path} {reverse path} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {reverse path} \l__spath_tmpb_tl
+ {
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+
+ \spath_put:nnV {#1} {reverse path} \l__spath_tmpa_tl
+ }
+ }
+
+ \__spath_get:nnNT {tmp_path} {length} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {length} \l__spath_tmpb_tl
+ {
+ \int_set:Nn \l__spath_tmpa_int {\l__spath_tmpa_tl + \l__spath_tmpb_tl - 1}
+ \spath_put:nnV {#1} {length} \l__spath_tmpa_int
+ }
+ }
+
+ \__spath_get:nnNT {tmp_path} {real length} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {real length} \l__spath_tmpb_tl
+ {
+ \int_set:Nn \l__spath_tmpa_int {\l__spath_tmpa_tl + \l__spath_tmpb_tl}
+ \spath_put:nnV {#1} {real length} \l__spath_tmpa_int
+ }
+ }
+
+ \__spath_get:nnNT {tmp_path} {number of components} \l__spath_tmpa_tl
+ {
+ \__spath_get:nnNT {#1} {number of components} \l__spath_tmpb_tl
+ {
+ \int_set:Nn \l__spath_tmpa_int {\l__spath_tmpa_tl + \l__spath_tmpb_tl - 1}
+ \spath_put:nnV {#1} {number of components} \l__spath_tmpa_int
+ }
+ }
+
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_prepend_no_move:nn}
+% Prepend the path from the second \Verb+spath+ to the first, removing
+% the adjoining move.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_prepend_no_move:nn #1#2
+{
+ \spath_if_exist:nT {#2}
+ {
+ \__spath_get:nnN {#2} {path} \l__spath_tmpa_tl
+ \__spath_get:nnN {#1} {path} \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+ \spath_put:nnV {#1} {path} \l__spath_tmpa_tl
+
+ \spath_if_in:nnTF {#2} {initial point}
+ {
+ \__spath_get:nnN {#2} {initial point} \l__spath_tmpa_tl
+ \spath_put:nnV {#1} {initial point} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {initial point}
+ }
+
+ \spath_if_in:nnTF {#2} {initial action}
+ {
+ \__spath_get:nnN {#2} {initial action} \l__spath_tmpa_tl
+ \spath_put:nnV {#1} {initial action} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {initial action}
+ }
+
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {length}
+ &&
+ \spath_if_in_p:nn {#2} {length}
+ }
+ {
+ \__spath_get:nnN {#1} {length} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {length} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {length} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl - 1}}
+ }
+ {
+ \spath_remove:nn {#1} {length}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {real length}
+ &&
+ \spath_if_in_p:nn {#2} {real length}
+ }
+ {
+ \__spath_get:nnN {#1} {real length} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {real length} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {real length} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl }}
+ }
+ {
+ \spath_remove:nn {#1} {real length}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {number of components}
+ &&
+ \spath_if_in_p:nn {#2} {number of components}
+ }
+ {
+ \__spath_get:nnN {#1} {number of components} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {number of components} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {number of components} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl - 1}}
+ }
+ {
+ \spath_remove:nn {#1} {number of components}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {min bb}
+ &&
+ \spath_if_in_p:nn {#2} {min bb}
+ }
+ {
+ \__spath_get:nnN {#1} {min bb} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {min bb} \l__spath_tmpb_tl
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {1}} {\tl_item:Nn
+ \l__spath_tmpb_tl {1}}}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {2}} {\tl_item:Nn
+ \l__spath_tmpb_tl {2}}}
+ \spath_put:nnx {#1} {min bb} {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ {
+ \spath_remove:nn {#1} {min bb}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {max bb}
+ &&
+ \spath_if_in_p:nn {#2} {max bb}
+ }
+ {
+ \__spath_get:nnN {#1} {max bb} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {max bb} \l__spath_tmpb_tl
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {1}} {\tl_item:Nn
+ \l__spath_tmpb_tl {1}}}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {2}} {\tl_item:Nn
+ \l__spath_tmpb_tl {2}}}
+ \spath_put:nnx {#1} {max bb} {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ {
+ \spath_remove:nn {#1} {max bb}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {reverse path}
+ &&
+ \spath_if_in_p:nn {#2} {reverse path}
+ }
+ {
+ \__spath_get:nnN {#1} {reverse path} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {reverse path} \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+ \spath_put:nnV {#1} {reverse path} \l__spath_tmpb_tl
+ }
+ {
+ \spath_remove:nn {#1} {reverse path}
+ }
+
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_append_no_move:nn}
+% Append the path from the second \Verb+spath+ to the first, removing
+% the adjoining move.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_append_no_move:nn #1#2
+{
+ \spath_if_exist:nT {#2}
+ {
+ \spath_get:nnN {#1} {path} \l__spath_tmpa_tl
+ \spath_get:nnN {#2} {path} \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+ \spath_put:nnV {#1} {path} \l__spath_tmpa_tl
+ \spath_if_in:nnTF {#2} {final point}
+ {
+ \__spath_get:nnN {#2} {final point} \l__spath_tmpa_tl
+ \spath_put:nnV {#1} {final point} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {final point}
+ }
+ \spath_if_in:nnTF {#2} {final action}
+ {
+ \__spath_get:nnN {#2} {final action} \l__spath_tmpa_tl
+ \spath_put:nnV {#1} {final action} \l__spath_tmpa_tl
+ }
+ {
+ \spath_remove:nn {#1} {final action}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {length}
+ &&
+ \spath_if_in_p:nn {#2} {length}
+ }
+ {
+ \__spath_get:nnN {#1} {length} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {length} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {length} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl - 1}}
+ }
+ {
+ \spath_remove:nn {#1} {length}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {real length}
+ &&
+ \spath_if_in_p:nn {#2} {real length}
+ }
+ {
+ \__spath_get:nnN {#1} {real length} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {real length} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {real length} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl }}
+ }
+ {
+ \spath_remove:nn {#1} {real length}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {number of components}
+ &&
+ \spath_if_in_p:nn {#2} {number of components}
+ }
+ {
+ \__spath_get:nnN {#1} {number of components} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {number of components} \l__spath_tmpb_tl
+ \spath_put:nnx {#1} {number of components} {\int_eval:n {\l__spath_tmpa_tl +
+ \l__spath_tmpb_tl - 1}}
+ }
+ {
+ \spath_remove:nn {#1} {number of components}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {min bb}
+ &&
+ \spath_if_in_p:nn {#2} {min bb}
+ }
+ {
+ \__spath_get:nnN {#1} {min bb} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {min bb} \l__spath_tmpb_tl
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {1}} {\tl_item:Nn
+ \l__spath_tmpb_tl {1}}}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {2}} {\tl_item:Nn
+ \l__spath_tmpb_tl {2}}}
+ \spath_put:nnx {#1} {min bb} {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ {
+ \spath_remove:nn {#1} {min bb}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {max bb}
+ &&
+ \spath_if_in_p:nn {#2} {max bb}
+ }
+ {
+ \__spath_get:nnN {#1} {max bb} \l__spath_tmpa_tl
+ \__spath_get:nnN {#2} {max bb} \l__spath_tmpb_tl
+ \dim_set:Nn \l__spath_tmpa_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {1}} {\tl_item:Nn
+ \l__spath_tmpb_tl {1}}}
+ \dim_set:Nn \l__spath_tmpb_dim {\dim_min:nn {\tl_item:Nn
+ \l__spath_tmpa_tl {2}} {\tl_item:Nn
+ \l__spath_tmpb_tl {2}}}
+ \spath_put:nnx {#1} {max bb} {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ }
+ {
+ \spath_remove:nn {#1} {max bb}
+ }
+ \bool_if:nTF
+ {
+ \spath_if_in_p:nn {#1} {reverse path}
+ &&
+ \spath_if_in_p:nn {#2} {reverse path}
+ }
+ {
+ \__spath_get:nnN {#2} {reverse path} \l__spath_tmpa_tl
+ \__spath_get:nnN {#1} {reverse path} \l__spath_tmpb_tl
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+ \spath_put:nnV {#1} {reverse path} \l__spath_tmpb_tl
+ }
+ {
+ \spath_remove:nn {#1} {reverse path}
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Iteration Functions}
+%
+% \begin{macro}{\spath_map_component:Nn}
+% This iterates through the components of a path, applying the inline function to each.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_map_component:Nn #1#2
+{
+ \int_gincr:N \g__prg_map_int
+ \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2}
+ \tl_set:NV \l__spath_tmpa_tl #1
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_moveto_tl
+ \tl_set_eq:NN \l__spath_tmpb_tl \g__spath_moveto_tl
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_if_eq:NNT \l__spath_tmpc_tl \g__spath_moveto_tl
+ {
+ \exp_args:NnV \use:c { __prg_map_ \int_use:N \g__prg_map_int :w } \l__spath_tmpb_tl
+\tl_clear:N \l__spath_tmpb_tl
+ }
+ \tl_if_single:NTF \l__spath_tmpc_tl
+ {
+ \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl
+ }
+ {
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\l__spath_tmpc_tl}}
+ }
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_map_segment_inline:Nn}
+% This iterates through the segments of the path, applying the inline function to each.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_map_segment_inline:Nn #1#2
+{
+ \int_gincr:N \g__prg_map_int
+ \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 ##2 {#2}
+ \spath_map_segment_function:Nc #1 { __prg_map_ \int_use:N \g__prg_map_int :w }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_map_segment_inline:nn}
+% This iterates through the segments of the path of the \Verb+spath+ object, applying the inline function to each.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_map_segment_inline:nn #1#2
+{
+ \int_gincr:N \g__prg_map_int
+ \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 ##2 {#2}
+ \spath_get:nnN {#1} {path} \l__spath_tmpd_tl
+ \spath_map_segment_function:Nc \l__spath_tmpd_tl { __prg_map_ \int_use:N \g__prg_map_int :w }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\spath_map_segment_function:nN}
+% This iterates through the segments of the path of the \Verb+spath+ object, applying the specified function to each.
+% The specified function should take two \Verb+N+ type arguments.
+% The first is a token representing the type of path segment, the second is the path segment itself.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_map_segment_function:nN #1#2
+{
+ \spath_get:nnN {#1} {path} \l__spath_tmpd_tl
+ \spath_map_segment_function:NN \l__spath_tmpd_tl #2
+}
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_map_segment_function:NN #1#2
+{
+ \tl_set_eq:NN \l__spath_tmpa_tl #1
+ \tl_clear:N \l__spath_tmpb_tl
+ \dim_zero:N \l__spath_tmpa_dim
+ \dim_zero:N \l__spath_tmpb_dim
+
+ \bool_until_do:nn {
+ \tl_if_empty_p:N \l__spath_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_case:Nnn \l__spath_tmpc_tl
+ {
+ \g__spath_lineto_tl
+ {
+ \tl_set_eq:NN \l__spath_tmpb_tl \g__spath_moveto_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \tl_put_right:NV \l__spath_tmpb_tl \g__spath_lineto_tl
+
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ }
+
+ \g__spath_curvetoa_tl
+ {
+ \tl_set_eq:NN \l__spath_tmpb_tl \g__spath_moveto_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl
+ {
+ {\dim_use:N \l__spath_tmpa_dim}
+ {\dim_use:N \l__spath_tmpb_dim}
+ }
+ \tl_put_right:NV \l__spath_tmpb_tl \g__spath_curvetoa_tl
+
+ \prg_replicate:nn {2} {
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+ }
+
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ }
+ }
+ {
+
+ \tl_set_eq:NN \l__spath_tmpb_tl \l__spath_tmpc_tl
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+ \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+ \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+ }
+
+ #2 \l__spath_tmpc_tl \l__spath_tmpb_tl
+ \tl_clear:N \l__spath_tmpb_tl
+
+ }
+}
+\cs_generate_variant:Nn \spath_map_segment_function:NN {Nc}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Public Commands}
+%
+% The next functions are more ``public'' than the previous lot.
+% That said, they aren't intended for direct use in a normal document.
+%
+% Most are just wrappers around internal functions.
+%
+% \begin{macro}{\MakeSPath}
+% Constructs an \Verb+spath+ object out of the given name and path.
+% \begin{macrocode}
+\NewDocumentCommand \MakeSPath { m m }
+{
+ \spath_clear_new:n {#1}
+ \spath_put:nno {#1} {path} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\MakeSPathList}
+% This constructs a list of \Verb+spath+ objects from a single path by splitting it into components.
+% \begin{macrocode}
+\NewDocumentCommand \MakeSPathList { m m }
+{
+ \tl_gclear_new:c {l__spath_list_#1}
+ \int_zero:N \l__spath_tmpa_int
+ \spath_map_component:Nn #2 {
+ \spath_clear_new:n {#1 _ \int_use:N \l__spath_tmpa_int}
+ \spath_put:nnn {#1 _ \int_use:N \l__spath_tmpa_int} {path} {##1}
+ \tl_gput_right:cx {l__spath_list_#1} {{#1 _ \int_use:N \l__spath_tmpa_int}}
+ \int_incr:N \l__spath_tmpa_int
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\CloneSPath}
+% \begin{macrocode}
+\NewDocumentCommand \CloneSPath { m m }
+{
+ \spath_clone:nn {#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathInfo}
+% \begin{macrocode}
+\NewDocumentCommand \SPathInfo { m m }
+{
+ \spath_get:nn {#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathPrepare}
+% \begin{macrocode}
+\NewDocumentCommand \SPathPrepare { m }
+{
+ \spath_generate_all:n {#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathListPrepare}
+% \begin{macrocode}
+\NewDocumentCommand \SPathListPrepare { m }
+{
+ \tl_map_inline:cn {l__spath_list_#1}
+ {
+ \spath_generate_all:n {##1}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathInfoInto}
+% \begin{macrocode}
+\NewDocumentCommand \SPathInfoInto { m m m }
+{
+ \tl_set:Nn \l_tmpa_tl #3
+ \spath_get:nnV {#1} {#2} \l_tmpa_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathShow}
+% \begin{macrocode}
+\NewDocumentCommand \SPathShow { m m }
+{
+ \spath_show:n {#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathTranslate}
+% \begin{macrocode}
+\NewDocumentCommand \SPathTranslate { m m m }
+{
+ \spath_translate:nnn {#1} {#2} {#3}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathTranslateInto}
+% Clones the path before translating it.
+% \begin{macrocode}
+\NewDocumentCommand \SPathTranslateInto { m m m m }
+{
+ \spath_clone:nn {#1} {#2}
+ \spath_translate:nnn {#2} {#3} {#4}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathScale}
+% \begin{macrocode}
+\NewDocumentCommand \SPathScale { m m m }
+{
+ \spath_translate:nnn {#1} {#2} {#3}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathScaleInto}
+% Clones the path first.
+% \begin{macrocode}
+\NewDocumentCommand \SPathScaleInto { m m m m }
+{
+ \spath_clone:nn {#1} {#2}
+ \spath_translate:nnn {#2} {#3} {#4}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathWeld}
+% \begin{macrocode}
+\NewDocumentCommand \SPathWeld { m m }
+{
+ \spath_weld:nn {#1} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\SPathWeldInto}
+% \begin{macrocode}
+\NewDocumentCommand \SPathWeldInto { m m m }
+{
+ \spath_clone:nn {#1} {#2}
+ \spath_weld:nn {#2} {#3}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Interfaces via TikZ keys.
+% \begin{macrocode}
+\tikzset{
+ save~spath/.code={
+ \tikz@addmode{
+ \spath_get_current_path:n {#1}
+ }
+ },
+ restore~spath/.code={
+ \spath_set_current_path:n {#1}
+ },
+}
+% \end{macrocode}
+% \subsection{Miscellaneous Commands}
+%
+% \begin{macro}{\spath_split_curve:nnNN}
+% Splits a Bezier cubic into pieces.
+% \begin{macrocode}
+\cs_new_nopar:Npn \spath_split_curve:nnNN #1#2#3#4
+{
+ \group_begin:
+ \tl_gclear:N \l__spath_smuggle_tl
+ \tl_set_eq:NN \l__spath_tmpa_tl \g__spath_moveto_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl {
+ {\tl_item:nn {#2} {3}}
+ {\tl_item:nn {#2} {4}}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetoa_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1) * \tl_item:nn {#2} {2} + (#1) * \tl_item:nn {#2} {5}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1) * \tl_item:nn {#2} {3} + (#1) * \tl_item:nn {#2} {6}
+ }}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetob_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1)^2 * \tl_item:nn {#2} {2} + 2 * (1 - #1) * (#1) * \tl_item:nn {#2} {5} + (#1)^2 * \tl_item:nn {#2} {8}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1)^2 * \tl_item:nn {#2} {3} + 2 * (1 - #1) * (#1) * \tl_item:nn {#2} {6} + (#1)^2 * \tl_item:nn {#2} {9}
+ }}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curveto_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1)^3 * \tl_item:nn {#2} {2} + 3 * (1 - #1)^2 * (#1) * \tl_item:nn {#2} {5} + 3 * (1 - #1) * (#1)^2 * \tl_item:nn {#2} {8} + (#1)^3 * \tl_item:nn {#2} {11}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1)^3 * \tl_item:nn {#2} {3} + 3 * (1 - #1)^2 * (#1) * \tl_item:nn {#2} {6} + 3 * (1 - #1) * (#1)^2 * \tl_item:nn {#2} {9} + (#1)^3 * \tl_item:nn {#2} {12}
+ }}
+ }
+ \tl_gset_eq:NN \l__spath_smuggle_tl \l__spath_tmpa_tl
+ \group_end:
+ \tl_set_eq:NN #3 \l__spath_smuggle_tl
+ \group_begin:
+ \tl_set_eq:NN \l__spath_tmpa_tl \g__spath_moveto_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1)^3 * \tl_item:nn {#2} {2} + 3 * (1 - #1)^2 * (#1) * \tl_item:nn {#2} {5} + 3 * (1 - #1) * (#1)^2 * \tl_item:nn {#2} {8} + (#1)^3 * \tl_item:nn {#2} {11}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1)^3 * \tl_item:nn {#2} {3} + 3 * (1 - #1)^2 * (#1) * \tl_item:nn {#2} {6} + 3 * (1 - #1) * (#1)^2 * \tl_item:nn {#2} {9} + (#1)^3 * \tl_item:nn {#2} {12}
+ }}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetoa_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1)^2 * \tl_item:nn {#2} {5} + 2 * (1 - #1) * (#1) * \tl_item:nn {#2} {8} + (#1)^2 * \tl_item:nn {#2} {11}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1)^2 * \tl_item:nn {#2} {6} + 2 * (1 - #1) * (#1) * \tl_item:nn {#2} {9} + (#1)^2 * \tl_item:nn {#2} {12}
+ }}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetob_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl
+ {
+ {\fp_to_dim:n
+ {
+ (1 - #1) * \tl_item:nn {#2} {8} + (#1) * \tl_item:nn {#2} {11}
+ }}
+ {\fp_to_dim:n
+ {
+ (1 - #1) * \tl_item:nn {#2} {9} + (#1) * \tl_item:nn {#2} {12}
+ }}
+ }
+ \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curveto_tl
+ \tl_put_right:Nx \l__spath_tmpa_tl {
+ {\tl_item:nn {#2} {11}}
+ {\tl_item:nn {#2} {12}}
+ }
+ \tl_gset_eq:NN \l__spath_smuggle_tl \l__spath_tmpa_tl
+ \group_end:
+ \tl_set_eq:NN #4 \l__spath_smuggle_tl
+}
+
+\cs_generate_variant:Nn \spath_split_curve:nnNN {nVNN, VVNN}
+% \end{macrocode}
+% \end{macro}
+% \iffalse
+%</spath3>
+% \fi
+%
+% \iffalse
+%<*calligraphy>
+% \fi
+%
+% \section{The Calligraphy Package}
+%
+% \subsection{Initialisation}
+% \begin{macrocode}
+\RequirePackage{spath3}
+\ExplSyntaxOn
+
+\tl_new:N \l__cal_tmpa_tl
+\tl_new:N \l__cal_tmpb_tl
+\int_new:N \l__cal_tmpa_int
+\int_new:N \l__cal_tmpb_int
+\int_new:N \l__cal_path_component_int
+\dim_new:N \l__cal_tmpa_dim
+\dim_new:N \l__cal_tmpb_dim
+\dim_new:N \l__cal_tmpc_dim
+\dim_new:N \l__cal_tmpd_dim
+\dim_new:N \l__cal_tmpe_dim
+\dim_new:N \l__cal_tmpf_dim
+\dim_new:N \l__cal_tmpg_dim
+\dim_new:N \l__cal_tmph_dim
+\bool_new:N \l__cal_taper_start_bool
+\bool_new:N \l__cal_taper_end_bool
+\bool_new:N \l__cal_taperable_bool
+\dim_new:N \l__cal_taper_width_dim
+\dim_new:N \l__cal_line_width_dim
+
+\bool_set_true:N \l__cal_taper_start_bool
+\bool_set_true:N \l__cal_taper_end_bool
+% \end{macrocode}
+%
+% \subsection{TikZ Keys}
+%
+% The public interface to this package is through TikZ keys and styles.
+% \begin{macrocode}
+\tikzset{
+ define~pen/.code={
+ \tikzset{pen~name=#1}
+ \pgf@relevantforpicturesizefalse
+ \tikz@addmode{
+ \pgfsyssoftpath@getcurrentpath\l__cal_tmpa_tl
+ \MakeSPathList{calligraphy pen \pgfkeysvalueof{/tikz/pen~name}}{\l__cal_tmpa_tl}
+ \SPathListPrepare{calligraphy pen \pgfkeysvalueof{/tikz/pen~name}}
+ \pgfusepath{discard}%
+ }
+ },
+ define~pen/.default={default},
+ use~pen/.code={
+ \tikzset{pen~name=#1}
+ \int_gzero:N \l__cal_path_component_int
+ \cs_set_eq:NN \pgfpathmoveto \cal_moveto:n
+ \tikz@addmode{
+ \pgfsyssoftpath@getcurrentpath\l__cal_tmpa_tl
+ \MakeSPathList{calligraphy path}{\l__cal_tmpa_tl}
+ \SPathListPrepare{calligraphy path}
+ \CalligraphyPathCreate{calligraphy path}{\pgfkeysvalueof{/tikz/pen~name}}
+ }
+ },
+ use~pen/.default={default},
+ pen~name/.initial={default},
+ copperplate/.style={pen~name=copperplate},
+ pen~colour/.initial={black},
+ weight/.is~choice,
+ weight/heavy/.style={
+ line~width=\pgfkeysvalueof{/tikz/heavy~line~width},
+ taper~width=\pgfkeysvalueof{/tikz/light~line~width},
+ },
+ weight/light/.style={
+ line~width=\pgfkeysvalueof{/tikz/light~line~width},
+ taper~width=0pt,
+ },
+ heavy/.style={
+ weight=heavy
+ },
+ light/.style={
+ weight=light
+ },
+ heavy~line~width/.initial=2pt,
+ light~line~width/.initial=1pt,
+ taper/.is~choice,
+ taper/.default=both,
+ taper/none/.style={
+ taper~start=false,
+ taper~end=false,
+ },
+ taper/both/.style={
+ taper~start=true,
+ taper~end=true,
+ },
+ taper/start/.style={
+ taper~start=true,
+ taper~end=false,
+ },
+ taper/end/.style={
+ taper~start=false,
+ taper~end=true,
+ },
+ taper~start/.code={
+ \tl_if_eq:nnTF {#1} {true}
+ {
+ \bool_set_true:N \l__cal_taper_start_bool
+ }
+ {
+ \bool_set_false:N \l__cal_taper_start_bool
+ }
+ },
+ taper~start/.default={true},
+ taper~end/.code={
+ \tl_if_eq:nnTF {#1} {true}
+ {
+ \bool_set_true:N \l__cal_taper_end_bool
+ }
+ {
+ \bool_set_false:N \l__cal_taper_end_bool
+ }
+ },
+ taper~end/.default={true},
+ taper~width/.code={\dim_set:Nn \l__cal_taper_width_dim {#1}},
+ nib~style/.code~2~args={
+ \tl_clear_new:c {l__cal_nib_style_#1}
+ \tl_set:cn {l__cal_nib_style_#1} {#2}
+ },
+ stroke~style/.code~2~args={
+ \tl_clear_new:c {l__cal_stroke_style_#1}
+ \tl_set:cn {l__cal_stroke_style_#1} {#2}
+ },
+ this~stroke~style/.code={
+ \tl_clear_new:c {l__cal_stroke_inline_style_ \int_use:N \l__cal_path_component_int}
+ \tl_set:cn {l__cal_stroke_inline_style_ \int_use:N \l__cal_path_component_int} {#1}
+ },
+}
+% \end{macrocode}
+%
+% Some wrappers around the TikZ keys.
+% \begin{macrocode}
+\NewDocumentCommand \pen { O{} }
+{
+ \path[define~ pen,#1]
+}
+
+\NewDocumentCommand \definepen { O{} }
+{
+ \tikz \path[define~ pen,#1]
+}
+
+\NewDocumentCommand \calligraphy { O{} }
+{
+ \path[use~ pen,#1]
+}
+% \end{macrocode}
+%
+% \subsection{The Path Creation}
+%
+% \begin{macro}{\CalligraphyPathCreate}
+% This is the main command for creating the calligraphic paths.
+% \begin{macrocode}
+\NewDocumentCommand \CalligraphyPathCreate { m m }
+{
+ \int_zero:N \l__cal_tmpa_int
+ \tl_map_inline:cn {l__spath_list_#1}
+ {
+ \int_incr:N \l__cal_tmpa_int
+ \int_zero:N \l__cal_tmpb_int
+ \tl_map_inline:cn {l__spath_list_calligraphy pen #2}
+ {
+ \int_incr:N \l__cal_tmpb_int
+ \group_begin:
+ \cal_apply_style:c {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int}
+ \cal_apply_style:c {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int}
+ \cal_apply_style:c {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int}
+
+ \spath_clone:nn {##1} {calligraphy temp path}
+
+ \__spath_get:nnN {####1} {initial point} \l__spath_tmpa_tl
+ \spath_translate:nV {calligraphy temp path} \l__spath_tmpa_tl
+
+ \__spath_get:nnN {####1} {length} \l__spath_tmpa_tl
+
+ \int_compare:nTF {\l__spath_tmpa_tl = 1}
+ {
+ \cal_at_least_three:n {calligraphy temp path}
+
+ \spath_protocol_path:n {calligraphy temp path}
+
+ \__spath_get:nnN {calligraphy temp path} {path} \l__spath_tmpa_tl
+
+ \tikz@options
+ \dim_set:Nn \l__cal_line_width_dim {\pgflinewidth}
+ \cal_maybe_taper:N \l__spath_tmpa_tl
+ }
+ {
+
+ \spath_weld:nn {calligraphy temp path} {####1}
+ \spath_reverse:n {##1}
+ \spath_reverse:n {####1}
+ \spath_weld:nn {calligraphy temp path} {##1}
+ \spath_weld:nn {calligraphy temp path} {####1}
+ \spath_reverse:n {##1}
+ \spath_reverse:n {####1}
+
+ \spath_set_current_path:n {calligraphy temp path}
+
+ \tikz@options
+ \pgfsetfillcolor{\pgfkeysvalueof{/tikz/pen~colour}}
+ \pgfusepath{fill}
+ }
+ \group_end:
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_moveto:n}
+% When creating the path, we need to keep track of the number of components so that we can apply styles accordingly.
+% \begin{macrocode}
+\cs_new_eq:NN \cal_orig_moveto:n \pgfpathmoveto
+\cs_new_nopar:Npn \cal_moveto:n #1
+{
+ \int_gincr:N \l__cal_path_component_int
+ \cal_orig_moveto:n {#1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_apply_style:N}
+% Interface for applying \Verb+\tikzset+ to a token list.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_apply_style:N #1
+{
+ \tl_if_exist:NT #1 {
+ \exp_args:NV \tikzset #1
+ }
+}
+\cs_generate_variant:Nn \cal_apply_style:N {c}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_at_least_three:n}
+% A tapered path has to have at least three components.
+% This figures out if it is necessary and sets up the splitting.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_at_least_three:n #1
+{
+ \spath_get:nnN {#1} {real length} \l__cal_tmpa_tl
+ \tl_clear:N \l__cal_tmpb_tl
+ \int_compare:nTF {\l__cal_tmpa_tl = 1}
+ {
+ \spath_get:nnN {#1} {path} \l__cal_tmpa_tl
+ \spath_map_segment_inline:Nn \l__cal_tmpa_tl
+ {
+ \tl_case:Nnn ##1 {
+ \g__spath_lineto_tl {
+ \cal_split_line_in_three:NN \l__cal_tmpb_tl ##2
+ }
+ \g__spath_curvetoa_tl {
+ \cal_split_curve_in_three:NN \l__cal_tmpb_tl ##2
+ }
+ }
+ {
+ \tl_put_right:NV \l__cal_tmpb_tl ##2
+ }
+ }
+ \spath_put:nnV {#1} {path} \l__cal_tmpb_tl
+ }
+ {
+ \int_compare:nT {\l__cal_tmpa_tl = 2}
+ {
+ \spath_get:nnN {#1} {path} \l__cal_tmpa_tl
+ \spath_map_segment_inline:Nn \l__cal_tmpa_tl
+ {
+ \tl_case:Nnn ##1 {
+ \g__spath_lineto_tl {
+ \cal_split_line_in_two:NN \l__cal_tmpb_tl ##2
+ }
+ \g__spath_curvetoa_tl {
+ \cal_split_curve_in_two:NN \l__cal_tmpb_tl ##2
+ }
+ }
+ {
+ \tl_put_right:NV \l__cal_tmpb_tl ##2
+ }
+ }
+ \spath_put:nnV {#1} {path} \l__cal_tmpb_tl
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_split_line_in_two:NN}
+% Splits a line in two, adding the splits to the first token list.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_split_line_in_two:NN #1#2
+{
+ \tl_set_eq:NN \l__cal_tmpc_tl #2
+
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpa_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpb_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpc_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+ \dim_set:Nn \l__cal_tmpd_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \tl_put_right:NV #1 \g__spath_lineto_tl
+
+ \tl_put_right:Nx #1 {
+ {\dim_eval:n {(\l__cal_tmpa_dim + \l__cal_tmpc_dim)/2}}
+ {\dim_eval:n {(\l__cal_tmpb_dim + \l__cal_tmpd_dim)/2}}
+ }
+
+ \tl_put_right:NV #1 \g__spath_lineto_tl
+ \tl_put_right:Nx #1 {
+ {\dim_use:N \l__cal_tmpc_dim}
+ {\dim_use:N \l__cal_tmpd_dim}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_split_line_in_three:NN}
+% Splits a line in three, adding the splits to the first token list.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_split_line_in_three:NN #1#2
+{
+ \tl_set_eq:NN \l__cal_tmpc_tl #2
+
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpa_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpb_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \dim_set:Nn \l__cal_tmpc_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+ \dim_set:Nn \l__cal_tmpd_dim {\tl_head:N \l__cal_tmpc_tl}
+ \tl_set:Nx \l__cal_tmpc_tl {\tl_tail:N \l__cal_tmpc_tl}
+
+ \tl_put_right:NV #1 \g__spath_lineto_tl
+
+ \tl_put_right:Nx #1 {
+ {\dim_eval:n {(2\l__cal_tmpa_dim + \l__cal_tmpc_dim)/3}}
+ {\dim_eval:n {(2\l__cal_tmpb_dim + \l__cal_tmpd_dim)/3}}
+ }
+
+ \tl_put_right:NV #1 \g__spath_lineto_tl
+
+ \tl_put_right:Nx #1 {
+ {\dim_eval:n {(\l__cal_tmpa_dim + 2\l__cal_tmpc_dim)/3}}
+ {\dim_eval:n {(\l__cal_tmpb_dim + 2\l__cal_tmpd_dim)/3}}
+ }
+
+ \tl_put_right:NV #1 \g__spath_lineto_tl
+ \tl_put_right:Nx #1 {
+ {\dim_use:N \l__cal_tmpc_dim}
+ {\dim_use:N \l__cal_tmpd_dim}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_split_curve_in_two:NN}
+% Splits a curve in two, adding the splits to the first token list.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_split_curve_in_two:NN #1#2
+{
+ \spath_split_curve:nVNN {.5} #2 \l_tmpa_tl \l_tmpb_tl
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_put_right:NV #1 \l_tmpa_tl
+ \tl_put_right:NV #1 \l_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_split_curve_in_three:NN}
+% Splits a curve in three, adding the splits to the first token list.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_split_curve_in_three:NN #1#2
+{
+ \spath_split_curve:nVNN {1/3} #2 \l_tmpa_tl \l_tmpb_tl
+
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_put_right:NV #1 \l_tmpa_tl
+
+ \spath_split_curve:nVNN {.5} \l_tmpb_tl \l_tmpa_tl \l_tmpb_tl
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_put_right:NV #1 \l_tmpa_tl
+ \tl_put_right:NV #1 \l_tmpb_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cal_maybe_taper:N}
+% Possibly tapers the path, depending on the booleans.
+% \begin{macrocode}
+\cs_new_nopar:Npn \cal_maybe_taper:N #1
+{
+ \tl_set_eq:NN \l__cal_tmpa_tl #1
+
+ \bool_if:NT \l__cal_taper_start_bool
+ {
+
+ \dim_set:Nn \l__cal_tmpa_dim {\tl_item:Nn \l__cal_tmpa_tl {2}}
+ \dim_set:Nn \l__cal_tmpb_dim {\tl_item:Nn \l__cal_tmpa_tl {3}}
+ \tl_set:Nx \l__cal_tmpb_tl {\tl_item:Nn \l__cal_tmpa_tl {4}}
+
+ \tl_case:Nnn \l__cal_tmpb_tl
+ {
+ \g__spath_lineto_tl
+ {
+
+ \bool_set_true:N \l__cal_taperable_bool
+ \dim_set:Nn \l__cal_tmpg_dim {\tl_item:Nn \l__cal_tmpa_tl {5}}
+ \dim_set:Nn \l__cal_tmph_dim {\tl_item:Nn \l__cal_tmpa_tl {6}}
+ \dim_set:Nn \l__cal_tmpc_dim {(2\l__cal_tmpa_dim + \l__cal_tmpg_dim)/3}
+ \dim_set:Nn \l__cal_tmpd_dim {(2\l__cal_tmpb_dim + \l__cal_tmph_dim)/3}
+ \dim_set:Nn \l__cal_tmpe_dim {(\l__cal_tmpa_dim + 2\l__cal_tmpg_dim)/3}
+ \dim_set:Nn \l__cal_tmpf_dim {(\l__cal_tmpb_dim + 2\l__cal_tmph_dim)/3}
+ \prg_replicate:nn {4}
+ {
+ \tl_set:Nx \l__cal_tmpa_tl {\tl_tail:N \l__cal_tmpa_tl}
+ }
+ \tl_put_left:NV \l__cal_tmpa_tl \g__spath_moveto_tl
+ }
+ \g__spath_curvetoa_tl
+ {
+ \bool_set_true:N \l__cal_taperable_bool
+ \dim_set:Nn \l__cal_tmpc_dim {\tl_item:Nn \l__cal_tmpa_tl {5}}
+ \dim_set:Nn \l__cal_tmpd_dim {\tl_item:Nn \l__cal_tmpa_tl {6}}
+ \dim_set:Nn \l__cal_tmpe_dim {\tl_item:Nn \l__cal_tmpa_tl {8}}
+ \dim_set:Nn \l__cal_tmpf_dim {\tl_item:Nn \l__cal_tmpa_tl {9}}
+ \dim_set:Nn \l__cal_tmpg_dim {\tl_item:Nn \l__cal_tmpa_tl {11}}
+ \dim_set:Nn \l__cal_tmph_dim {\tl_item:Nn \l__cal_tmpa_tl {12}}
+ \prg_replicate:nn {10}
+ {
+ \tl_set:Nx \l__cal_tmpa_tl {\tl_tail:N \l__cal_tmpa_tl}
+ }
+ \tl_put_left:NV \l__cal_tmpa_tl \g__spath_moveto_tl
+ }
+ }
+ {
+ \bool_set_false:N \l__cal_taperable_bool
+ }
+
+ \bool_if:NT \l__cal_taperable_bool
+ {
+ \__cal_taper_aux:
+ }
+
+ }
+
+ \bool_if:NT \l__cal_taper_end_bool
+ {
+
+ \dim_set:Nn \l__cal_tmpa_dim {\tl_item:Nn \l__cal_tmpa_tl {-2}}
+ \dim_set:Nn \l__cal_tmpb_dim {\tl_item:Nn \l__cal_tmpa_tl {-1}}
+ \tl_set:Nx \l__cal_tmpb_tl {\tl_item:Nn \l__cal_tmpa_tl {-3}}
+
+ \tl_case:Nnn \l__cal_tmpb_tl
+ {
+ \g__spath_lineto_tl
+ {
+
+ \bool_set_true:N \l__cal_taperable_bool
+ \dim_set:Nn \l__cal_tmpg_dim {\tl_item:Nn \l__cal_tmpa_tl {-5}}
+ \dim_set:Nn \l__cal_tmph_dim {\tl_item:Nn \l__cal_tmpa_tl {-4}}
+ \dim_set:Nn \l__cal_tmpc_dim {(2\l__cal_tmpa_dim + \l__cal_tmpg_dim)/3}
+ \dim_set:Nn \l__cal_tmpd_dim {(2\l__cal_tmpb_dim + \l__cal_tmph_dim)/3}
+ \dim_set:Nn \l__cal_tmpe_dim {(\l__cal_tmpa_dim + 2\l__cal_tmpg_dim)/3}
+ \dim_set:Nn \l__cal_tmpf_dim {(\l__cal_tmpb_dim + 2\l__cal_tmph_dim)/3}
+ \tl_reverse:N \l__cal_tmpa_tl
+ \prg_replicate:nn {3}
+ {
+ \tl_set:Nx \l__cal_tmpa_tl {\tl_tail:N \l__cal_tmpa_tl}
+ }
+ \tl_reverse:N \l__cal_tmpa_tl
+ }
+ \g__spath_curveto_tl
+ {
+ \bool_set_true:N \l__cal_taperable_bool
+ \dim_set:Nn \l__cal_tmpc_dim {\tl_item:Nn \l__cal_tmpa_tl {-5}}
+ \dim_set:Nn \l__cal_tmpd_dim {\tl_item:Nn \l__cal_tmpa_tl {-4}}
+ \dim_set:Nn \l__cal_tmpe_dim {\tl_item:Nn \l__cal_tmpa_tl {-8}}
+ \dim_set:Nn \l__cal_tmpf_dim {\tl_item:Nn \l__cal_tmpa_tl {-7}}
+ \dim_set:Nn \l__cal_tmpg_dim {\tl_item:Nn \l__cal_tmpa_tl {-11}}
+ \dim_set:Nn \l__cal_tmph_dim {\tl_item:Nn \l__cal_tmpa_tl {-10}}
+ \tl_reverse:N \l__cal_tmpa_tl
+ \prg_replicate:nn {9}
+ {
+ \tl_set:Nx \l__cal_tmpa_tl {\tl_tail:N \l__cal_tmpa_tl}
+ }
+ \tl_reverse:N \l__cal_tmpa_tl
+ }
+ }
+ {
+ \bool_set_false:N \l__cal_taperable_bool
+ }
+
+ \bool_if:NT \l__cal_taperable_bool
+ {
+ \__cal_taper_aux:
+ }
+
+ }
+
+ \pgfsyssoftpath@setcurrentpath\l__cal_tmpa_tl
+ \pgfsetstrokecolor{\pgfkeysvalueof{/tikz/pen~colour}}
+ \pgfusepath{stroke}
+
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__cal_taper_aux:}
+% Auxiliary macro to avoid unnecessary code duplication.
+% \begin{macrocode}
+\cs_new_nopar:Npn \__cal_taper_aux:
+{
+ \tl_clear:N \l__cal_tmpb_tl
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_moveto_tl
+
+ \fp_set:Nn \l__cal_tmpa_fp
+ {
+ \l__cal_tmpd_dim - \l__cal_tmpb_dim
+ }
+ \fp_set:Nn \l__cal_tmpb_fp
+ {
+ \l__cal_tmpa_dim - \l__cal_tmpc_dim
+ }
+ \fp_set:Nn \l__cal_tmpe_fp
+ {
+ (\l__cal_tmpa_fp^2 + \l__cal_tmpb_fp^2)^.5
+ }
+
+ \fp_set:Nn \l__cal_tmpa_fp {.5*\l__cal_taper_width_dim * \l__cal_tmpa_fp / \l__cal_tmpe_fp}
+ \fp_set:Nn \l__cal_tmpb_fp {.5*\l__cal_taper_width_dim * \l__cal_tmpb_fp / \l__cal_tmpe_fp}
+
+ \fp_set:Nn \l__cal_tmpc_fp
+ {
+ \l__cal_tmph_dim - \l__cal_tmpf_dim
+ }
+ \fp_set:Nn \l__cal_tmpd_fp
+ {
+ \l__cal_tmpe_dim - \l__cal_tmpg_dim
+ }
+ \fp_set:Nn \l__cal_tmpe_fp
+ {
+ (\l__cal_tmpc_fp^2 + \l__cal_tmpd_fp^2)^.5
+ }
+
+ \fp_set:Nn \l__cal_tmpc_fp {.5*\l__cal_line_width_dim * \l__cal_tmpc_fp / \l__cal_tmpe_fp}
+ \fp_set:Nn \l__cal_tmpd_fp {.5*\l__cal_line_width_dim * \l__cal_tmpd_fp / \l__cal_tmpe_fp}
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpa_dim}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpb_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetoa_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpc_dim}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpd_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetob_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpe_dim}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmpf_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curveto_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpg_dim}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmph_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetoa_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpg_dim - \fp_to_dim:n{ 1.32 * \l__cal_tmpd_fp}}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmph_dim + \fp_to_dim:n {1.32* \l__cal_tmpc_fp}}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetob_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpg_dim - \fp_to_dim:n {1.32 * \l__cal_tmpd_fp}}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmph_dim + \fp_to_dim:n {1.32 * \l__cal_tmpc_fp}}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curveto_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpg_dim}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmph_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetoa_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpc_fp + \l__cal_tmpe_dim}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpd_fp + \l__cal_tmpf_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetob_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpc_dim}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpd_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curveto_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpa_dim}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpb_dim}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetoa_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpa_dim + \fp_to_dim:n{ 1.32 * \l__cal_tmpb_fp}}}
+ {\dim_eval:n { -\fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpb_dim - \fp_to_dim:n {1.32* \l__cal_tmpa_fp}}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curvetob_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpa_dim + \fp_to_dim:n {1.32 * \l__cal_tmpb_fp}}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpb_dim - \fp_to_dim:n {1.32 * \l__cal_tmpa_fp}}}
+ }
+
+ \tl_put_right:NV \l__cal_tmpb_tl \g__spath_curveto_tl
+
+ \tl_put_right:Nx \l__cal_tmpb_tl
+ {
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpa_fp + \l__cal_tmpa_dim}}
+ {\dim_eval:n { \fp_to_dim:N \l__cal_tmpb_fp + \l__cal_tmpb_dim}}
+ }
+
+ \pgfsyssoftpath@setcurrentpath\l__cal_tmpb_tl
+ \pgfsetfillcolor{\pgfkeysvalueof{/tikz/pen~colour}}
+ \pgfusepath{fill}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Defines a copperplate pen.
+% \begin{macrocode}
+\tl_set:Nn \l__cal_tmpa_tl {\pgfsyssoftpath@movetotoken{0pt}{0pt}}
+\MakeSPathList{calligraphy pen copperplate}{\l__cal_tmpa_tl}
+\SPathListPrepare{calligraphy pen copperplate}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+% \subsection{Decorations}
+%
+% If a decoration library is loaded we define some decorations that use the calligraphy library, specifically the copperplate pen with its tapering.
+%
+% First, a brace decoration.
+% \begin{macrocode}
+\expandafter\ifx\csname pgfdeclaredecoration\endcsname\relax
+\else
+\pgfdeclaredecoration{calligraphic brace}{brace}
+{
+ \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
+ {
+ \pgfsyssoftpath@setcurrentpath{\pgfutil@empty}
+ \pgfpathmoveto{\pgfpointorigin}
+ \pgfpathcurveto
+ {\pgfqpoint{.15\pgfdecorationsegmentamplitude}{.3\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{.5\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ {
+ \pgftransformxshift{+\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance}
+ \pgfpathlineto{\pgfqpoint{-\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ \pgfpathcurveto
+ {\pgfqpoint{-.5\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{-.15\pgfdecorationsegmentamplitude}{.7\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{0\pgfdecorationsegmentamplitude}{1\pgfdecorationsegmentamplitude}}
+ \pgfpathmoveto{\pgfqpoint{0\pgfdecorationsegmentamplitude}{1\pgfdecorationsegmentamplitude}}
+ \pgfpathcurveto
+ {\pgfqpoint{.15\pgfdecorationsegmentamplitude}{.7\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{.5\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ }
+ {
+ \pgftransformxshift{+\pgfdecoratedremainingdistance}
+ \pgfpathlineto{\pgfqpoint{-\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ \pgfpathcurveto
+ {\pgfqpoint{-.5\pgfdecorationsegmentamplitude}{.5\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{-.15\pgfdecorationsegmentamplitude}{.3\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{0pt}{0pt}}
+ }
+ \tikzset{
+ taper width=.5\pgflinewidth,
+ taper
+ }%
+ \pgfsyssoftpath@getcurrentpath\cal@tmp@path
+ \MakeSPathList{calligraphy path}{\cal@tmp@path}%
+ \SPathListPrepare{calligraphy path}%
+ \CalligraphyPathCreate{calligraphy path}{copperplate}%
+ }
+ \state{final}{}
+}
+% \end{macrocode}
+%
+% The second is a straightened parenthesis (so that when very large it doesn't bow out too far).
+% \begin{macrocode}
+\pgfdeclaredecoration{calligraphic straight parenthesis}{brace}
+{
+ \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
+ {
+ \pgfsyssoftpath@setcurrentpath{\pgfutil@empty}
+ \pgfpathmoveto{\pgfpointorigin}
+ \pgfpathcurveto
+ {\pgfqpoint{.76604\pgfdecorationsegmentamplitude}{.64279\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{2.3333\pgfdecorationsegmentamplitude}{\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{3.3333\pgfdecorationsegmentamplitude}{\pgfdecorationsegmentamplitude}}
+ {
+ \pgftransformxshift{+\pgfdecoratedremainingdistance}
+ \pgfpathlineto{\pgfqpoint{-3.3333\pgfdecorationsegmentamplitude}{\pgfdecorationsegmentamplitude}}
+ \pgfpathcurveto
+ {\pgfqpoint{-2.3333\pgfdecorationsegmentamplitude}{\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{-.76604\pgfdecorationsegmentamplitude}{.64279\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{0pt}{0pt}}
+ }
+ \tikzset{
+ taper width=.5\pgflinewidth,
+ taper
+ }%
+ \pgfsyssoftpath@getcurrentpath\cal@tmp@path
+ \MakeSPathList{calligraphy path}{\cal@tmp@path}%
+ \SPathListPrepare{calligraphy path}%
+ \CalligraphyPathCreate{calligraphy path}{copperplate}%
+ }
+ \state{final}{}%
+}
+% \end{macrocode}
+%
+% The third is a curved parenthesis.
+% \begin{macrocode}
+\pgfdeclaredecoration{calligraphic curved parenthesis}{brace}
+{
+ \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
+ {
+ \pgfsyssoftpath@setcurrentpath{\pgfutil@empty}
+ \pgfpathmoveto{\pgfpointorigin}
+ \pgf@xa=\pgfdecoratedremainingdistance\relax
+ \advance\pgf@xa by -1.5890\pgfdecorationsegmentamplitude\relax
+ \edef\cgrphy@xa{\the\pgf@xa}
+ \pgfpathcurveto
+ {\pgfqpoint{1.5890\pgfdecorationsegmentamplitude}{1.3333\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{\cgrphy@xa}{1.3333\pgfdecorationsegmentamplitude}}
+ {\pgfqpoint{\pgfdecoratedremainingdistance}{0pt}}
+ \tikzset{
+ taper width=.5\pgflinewidth,
+ taper
+ }%
+ \pgfsyssoftpath@getcurrentpath\cal@tmp@path
+ \MakeSPathList{calligraphy path}{\cal@tmp@path}%
+ \SPathListPrepare{calligraphy path}%
+ \CalligraphyPathCreate{calligraphy path}{copperplate}%
+ }
+ \state{final}{}%
+}
+% \end{macrocode}
+% End the conditional for if pgfdecoration module is loaded
+% \begin{macrocode}
+\fi
+% \end{macrocode}
+% \iffalse
+%</calligraphy>
+% \fi
+%
+%
+% \iffalse
+%<*knots>
+% \fi
+%%
+% \section{Drawing Knots}
+%
+%
+% \subsection{Initialisation}
+%
+% We load the \Verb+spath3+ library and the \Verb+intersections+ TikZ library.
+% Then we get going.
+% \begin{macrocode}
+\RequirePackage{spath3}
+\usetikzlibrary{intersections}
+
+\ExplSyntaxOn
+
+\tl_new:N \l__knot_tmpa_tl
+\tl_new:N \l__knot_tmpb_tl
+\tl_new:N \l__knot_tmpc_tl
+\tl_new:N \l__knot_tmpd_tl
+\tl_new:N \l__knot_tmpe_tl
+\tl_new:N \l__knot_tmpf_tl
+\tl_new:N \l__knot_tmpg_tl
+\tl_new:N \l__knot_redraws_tl
+\tl_new:N \l__knot_clip_width_tl
+\tl_new:N \l__knot_name_tl
+\tl_new:N \l__knot_node_tl
+
+\int_new:N \l__knot_tmpa_int
+\int_new:N \l__knot_strands_int
+\int_new:N \l__knot_intersections_int
+\int_new:N \l__knot_filaments_int
+\int_new:N \l__knot_component_start_int
+
+\dim_new:N \l__knot_tmpa_dim
+\dim_new:N \l__knot_tmpb_dim
+\dim_new:N \l__knot_tmpc_dim
+\dim_new:N \l__knot_tolerance_dim
+\dim_new:N \l__knot_clip_radius_dim
+
+\bool_new:N \l__knot_draft_bool
+\bool_new:N \l__knot_ignore_ends_bool
+\bool_new:N \l__knot_self_intersections_bool
+\bool_new:N \l__knot_splits_bool
+\bool_new:N \l__knot_super_draft_bool
+
+\bool_new:N \l__knot_prepend_prev_bool
+\bool_new:N \l__knot_append_next_bool
+\bool_new:N \l__knot_skip_bool
+
+\bool_set_true:N \l__knot_ignore_ends_bool
+% \end{macrocode}
+%
+% Configuration is via TikZ keys and styles.
+% \begin{macrocode}
+\tikzset{
+ knot/.code={
+ \tl_if_eq:nnTF {#1} {none}
+ {
+ \tikz@addmode{\tikz@mode@doublefalse}
+ }
+ {
+ \tikz@addmode{\tikz@mode@doubletrue}
+ \tl_if_empty:nTF {#1}
+ {
+ \pgfsetinnerstrokecolor{\tikz@strokecolor}
+ }
+ {
+ \pgfsetinnerstrokecolor{#1}
+ }
+ \tikz@addoption{\pgfsetstrokecolor{knotbg}}
+ \tl_set:Nn \tikz@double@setup{
+ \pgfsetinnerlinewidth{\pgflinewidth}
+ \pgfsetlinewidth{\dim_eval:n {\tl_use:N \l__knot_gap_tl \pgflinewidth}}
+ }
+ }
+ },
+ knot~ gap/.store~ in=\l__knot_gap_tl,
+ knot~ gap=3,
+ knot~ diagram/.is~family,
+ knot~ diagram/.unknown/.code={
+ \tl_set_eq:NN \l__knot_tmpa_tl \pgfkeyscurrentname
+ \pgfkeysalso{
+ /tikz/\l__knot_tmpa_tl=#1
+ }
+ },
+ background~ colour/.code={%
+ \colorlet{knotbg}{#1}%
+ },
+ background~ color/.code={%
+ \colorlet{knotbg}{#1}%
+ },
+ background~ colour=white,
+ knot~ diagram,
+ name/.store~in=\l__knot_name_tl,
+ name={knot},
+ every~ strand/.style={draw},
+ ignore~ endpoint~ intersections/.code={
+ \tl_if_eq:nnTF {#1} {true}
+ {
+ \bool_set_true:N \l__knot_ignore_ends_bool
+ }
+ {
+ \bool_set_false:N \l__knot_ignore_ends_bool
+ }
+ },
+ ignore~ endpoint~ intersections/.default=true,
+ consider~ self~ intersections/.is~choice,
+ consider~ self~ intersections/true/.code={
+ \bool_set_true:N \l__knot_self_intersections_bool
+ \bool_set_true:N \l__knot_splits_bool
+ },
+ consider~ self~ intersections/false/.code={
+ \bool_set_false:N \l__knot_self_intersections_bool
+ \bool_set_false:N \l__knot_splits_bool
+ },
+ consider~ self~ intersections/no~ splits/.code={
+ \bool_set_true:N \l__knot_self_intersections_bool
+ \bool_set_false:N \l__knot_splits_bool
+ },
+ consider~ self~ intersections/.default={true},
+ clip~ radius/.code={
+ \dim_set:Nn \l__knot_clip_radius_dim {#1}
+ },
+ clip~ radius=10pt,
+ end~ tolerance/.code={
+ \dim_set:Nn \l__knot_tolerance_dim {#1}
+ },
+ end~ tolerance=14pt,
+ clip~ width/.code={
+ \tl_set:Nn \l__knot_clip_width_tl {#1}
+ },
+ clip~ width=3,
+ flip~ crossing/.code={%
+ \tl_clear_new:c {l__knot_crossing_#1}
+ \tl_set:cn {l__knot_crossing_#1} {x}
+ },
+ draft~ mode/.is~ choice,
+ draft~ mode/off/.code={%
+ \bool_set_false:N \l__knot_draft_bool
+ \bool_set_false:N \l__knot_super_draft_bool
+ },
+ draft~ mode/crossings/.code={%
+ \bool_set_true:N \l__knot_draft_bool
+ \bool_set_false:N \l__knot_super_draft_bool
+ },
+ draft~ mode/strands/.code={%
+ \bool_set_true:N \l__knot_draft_bool
+ \bool_set_true:N \l__knot_super_draft_bool
+ },
+ draft/.is~ family,
+ draft,
+ crossing~ label/.style={
+ overlay,
+ fill=white,
+ fill~ opacity=.5,
+ text~ opacity=1,
+ text=blue,
+ pin~ edge={blue,<-}
+ },
+ strand~ label/.style={
+ overlay,
+ circle,
+ draw=purple,
+ fill=white,
+ fill~ opacity=.5,
+ text~ opacity=1,
+ text=purple,
+ inner~ sep=0pt
+ },
+}
+% \end{macrocode}
+%
+% Wrapper around \Verb+\tikzset+ for applying keys from a token list, checking for if the given token list exists.
+% \begin{macrocode}
+\cs_new_nopar:Npn \knot_apply_style:N #1
+{
+ \tl_if_exist:NT #1 {
+ \exp_args:NV \tikzset #1
+ }
+}
+\cs_generate_variant:Nn \knot_apply_style:N {c}
+% \end{macrocode}
+%
+%\begin{macro}{\flipcrossings}
+% The user can specify a comma separated list of crossings to flip.
+% \begin{macrocode}
+\NewDocumentCommand \flipcrossings {m}
+{
+ \tikzset{knot~ diagram/flip~ crossing/.list={#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\strand}
+% This is how the user specifies a strand of the knot.
+% \begin{macrocode}
+\NewDocumentCommand \strand { O{} }
+{
+ \int_incr:N \l__knot_strands_int
+ \tl_clear_new:c {l__knot_options_strand \int_use:N \l__knot_strands_int}
+ \tl_set:cn {l__knot_options_strand \int_use:N \l__knot_strands_int} {#1}
+ \path[#1,save~ spath=knot strand \int_use:N \l__knot_strands_int]
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot}
+% This is the wrapper environment that calls the knot generation code.
+% \begin{macrocode}
+\NewDocumentEnvironment{knot} { O{} }
+{
+ \knot_initialise:n {#1}
+}
+{
+ \knot_render:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_initialise:n}
+% Set up some stuff before loading in the strands.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_initialise:n #1
+{
+ \tikzset{knot~ diagram/.cd,every~ knot~ diagram/.try,#1}
+ \int_zero:N \l__knot_strands_int
+ \tl_clear:N \l__knot_redraws_tl
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_render:}
+% This is the code that starts the work of rendering the knot.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_render:
+{
+% \end{macrocode}
+% Start a scope and reset the transformation (since all transformations have already been taken into account when defining the strands).
+% \begin{macrocode}
+ \pgfscope
+ \pgftransformreset
+% \end{macrocode}
+% Loop through the strands drawing each one for the first time.
+% \begin{macrocode}
+ \int_step_function:nnnN {1} {1} {\l__knot_strands_int} \knot_draw_strand:n
+% \end{macrocode}
+% In super draft mode we don't do anything else.
+% \begin{macrocode}
+ \bool_if:NF \l__knot_super_draft_bool
+ {
+% \end{macrocode}
+% In draft mode we draw labels at the ends of the strands; this also handles splitting curves to avoid self-intersections of Bezier curves if that's requested.
+% \begin{macrocode}
+ \int_step_function:nnnN {1} {1} {\l__knot_strands_int} \knot_draw_labels:n
+% \end{macrocode}
+% If we're considering self intersections we need to split the strands into filaments.
+% \begin{macrocode}
+ \bool_if:NTF \l__knot_self_intersections_bool
+ {
+ \knot_split_strands:
+ \int_set_eq:NN \l__knot_tmpa_int \l__knot_filaments_int
+ \tl_set:Nn \l__knot_prefix_tl {filament}
+ }
+ {
+ \int_set_eq:NN \l__knot_tmpa_int \l__knot_strands_int
+ \tl_set:Nn \l__knot_prefix_tl {strand}
+ }
+% \end{macrocode}
+% Initialise the intersection count.
+% \begin{macrocode}
+ \int_gzero:N \l__knot_intersections_int
+% \end{macrocode}
+% If in draft mode we label the intersections, otherwise we just stick a coordinate at each one.
+% \begin{macrocode}
+ \bool_if:NTF \l__knot_draft_bool
+ {
+ \tl_set:Nn \l__knot_node_tl
+ {\node[coordinate,pin={[knot~ diagram/draft/crossing~ label]{\int_use:N \l__knot_intersections_int}}]}
+ }
+ {
+ \tl_set:Nn \l__knot_node_tl {\node[coordinate]}
+ }
+% \end{macrocode}
+% This double loop steps through the pieces (strands or filaments) and computes the intersections and does stuff with those.
+% \begin{macrocode}
+ \int_step_variable:nnnNn {1} {1} {\l__knot_tmpa_int - 1} \l__knot_tmpa_tl
+ {
+ \int_step_variable:nnnNn {\tl_use:N \l__knot_tmpa_tl + 1} {1} {\l__knot_tmpa_int} \l__knot_tmpb_tl
+ {
+ \knot_intersections:VV \l__knot_tmpa_tl \l__knot_tmpb_tl
+ }
+ }
+% \end{macrocode}
+% If any redraws were requested, do them here.
+% \begin{macrocode}
+ \tl_use:N \l__knot_redraws_tl
+ }
+% \end{macrocode}
+% Close the scope
+% \begin{macrocode}
+ \endpgfscope
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_draw_strand:n}
+% This renders a strand using the options originally specified.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_draw_strand:n #1
+{
+ \pgfscope
+ \group_begin:
+ \tl_set:Nn \l_tmpa_tl {knot~ diagram/every~ strand/.try,}
+ \tl_put_right:Nv \l_tmpa_tl {l__knot_options_strand #1}
+ \tl_put_right:Nn \l_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try}
+ \spath_tikz_path:Vn \l_tmpa_tl {knot strand #1}
+ \group_end:
+ \endpgfscope
+}
+\cs_generate_variant:Nn \tl_put_right:Nn {Nv}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_draw_labels:n}
+% Draw a label at each end of each strand, if in draft mode.
+% Also, if requested, split potentially self intersecting Bezier curves.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_draw_labels:n #1
+{
+ \bool_if:NT \l__knot_draft_bool
+ {
+ \spath_get:nnN {knot strand #1} {final point} \l__knot_tmpb_tl
+ \dim_set:Nn \l__knot_tmpa_dim {\tl_item:Nn \l__knot_tmpb_tl {1}}
+ \dim_set:Nn \l__knot_tmpb_dim {\tl_item:Nn \l__knot_tmpb_tl {2}}
+ \node[knot~ diagram/draft/strand~label] at (\l__knot_tmpa_dim,\l__knot_tmpb_dim) {#1};
+ \spath_get:nnN {knot strand #1} {initial point} \l__knot_tmpb_tl
+ \dim_set:Nn \l__knot_tmpa_dim {\tl_item:Nn \l__knot_tmpb_tl {1}}
+ \dim_set:Nn \l__knot_tmpb_dim {\tl_item:Nn \l__knot_tmpb_tl {2}}
+ \node[knot~ diagram/draft/strand~label] at (\l__knot_tmpa_dim,\l__knot_tmpb_dim) {#1};
+ }
+ \bool_if:nT {
+ \l__knot_self_intersections_bool
+ &&
+ \l__knot_splits_bool
+ }
+ {
+ \tl_clear:N \l__knot_tmpa_tl
+ \spath_map_segment_function:nN {knot strand #1} \knot_split_self_intersects:NN
+ \spath_put:nnV {knot strand #1} {path} \l__knot_tmpa_tl
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_split_self_intersects:NN}
+% This is the macro that does the split.
+% Figuring out whether a Bezier cubic self intersects is apparently a difficult problem so we don't bother.
+% We compute a point such that if there is an intersection then it lies on either side of the point.
+% I don't recall where the formula came from!
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_split_self_intersects:NN #1#2
+{
+ \tl_case:Nnn #1
+ {
+ \g__spath_curvetoa_tl
+ {
+ \fp_set:Nn \l_tmpa_fp
+ {
+ (\tl_item:Nn #2 {3} - 3 * \tl_item:Nn #2 {6} + 3 * \tl_item:Nn #2 {9} - \tl_item:Nn #2 {12})
+ *
+ (3 * \tl_item:Nn #2 {8} - 3 * \tl_item:Nn #2 {11})
+ -
+ (\tl_item:Nn #2 {2} - 3 * \tl_item:Nn #2 {5} + 3 * \tl_item:Nn #2 {8} - \tl_item:Nn #2 {11})
+ *
+ (3 * \tl_item:Nn #2 {9} - 3 * \tl_item:Nn #2 {12})
+ }
+ \fp_set:Nn \l_tmpb_fp
+ {
+ (\tl_item:Nn #2 {2} - 3 * \tl_item:Nn #2 {5} + 3 * \tl_item:Nn #2 {8} - \tl_item:Nn #2 {11})
+ *
+ (3 * \tl_item:Nn #2 {6} - 6 * \tl_item:Nn #2 {9} + 3 * \tl_item:Nn #2 {12})
+ -
+ (\tl_item:Nn #2 {3} - 3 * \tl_item:Nn #2 {6} + 3 * \tl_item:Nn #2 {9} - \tl_item:Nn #2 {12})
+ *
+ (3 * \tl_item:Nn #2 {5} - 6 * \tl_item:Nn #2 {8} + 3 * \tl_item:Nn #2 {11})
+ }
+ \fp_compare:nTF
+ {
+ \l_tmpb_fp != 0
+ }
+ {
+ \fp_set:Nn \l_tmpa_fp {.5 * \l_tmpa_fp / \l_tmpb_fp}
+ \fp_compare:nTF
+ {
+ 0 < \l_tmpa_fp && \l_tmpa_fp < 1
+ }
+ {
+ \spath_split_curve:VVNN \l_tmpa_fp #2 \l_tmpa_tl \l_tmpb_tl
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl}
+ \tl_put_right:NV \l__knot_tmpa_tl \l_tmpa_tl
+ \tl_put_right:NV \l__knot_tmpa_tl \l_tmpb_tl
+ }
+ {
+ \tl_set_eq:NN \l_tmpa_tl #2
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_put_right:NV \l__knot_tmpa_tl \l_tmpa_tl
+ }
+ }
+ {
+ \tl_set_eq:NN \l_tmpa_tl #2
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_put_right:NV \l__knot_tmpa_tl \l_tmpa_tl
+ }
+ }
+ \g__spath_lineto_tl
+ {
+ \tl_set_eq:NN \l_tmpa_tl #2
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
+ \tl_put_right:NV \l__knot_tmpa_tl \l_tmpa_tl
+ }
+ }
+ {
+ \tl_put_right:NV \l__knot_tmpa_tl #2
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_intersections:nn}
+% This computes the intersections of two pieces and steps through them.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_intersections:nn #1#2
+{
+ \group_begin:
+ \tl_set_eq:NN \l__knot_tmpa_tl \l__knot_prefix_tl
+ \tl_put_right:Nn \l__knot_tmpa_tl {#1}
+ \tl_set_eq:NN \l__knot_tmpb_tl \l__knot_prefix_tl
+ \tl_put_right:Nn \l__knot_tmpb_tl {#2}
+ \spath_get:nnN {knot \tl_use:N \l__knot_tmpa_tl} {path} \l__knot_tmpc_tl
+ \spath_get:nnN {knot \tl_use:N \l__knot_tmpb_tl} {path} \l__knot_tmpd_tl
+
+ \pgfintersectionofpaths{\pgfsetpath\l__knot_tmpc_tl}{\pgfsetpath\l__knot_tmpd_tl}
+
+ \int_compare:nT {\pgfintersectionsolutions > 0}
+ {
+ \int_step_function:nnnN {1} {1} {\pgfintersectionsolutions} \knot_do_intersection:n
+ }
+ \group_end:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_do_intersection:n}
+% This handles a specific intersection.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_do_intersection:n #1
+{
+% \end{macrocode}
+% Get the intersection coordinates.
+% \begin{macrocode}
+ \pgfpointintersectionsolution{#1}
+ \dim_set:Nn \l__knot_tmpa_dim {\pgf@x}
+ \dim_set:Nn \l__knot_tmpb_dim {\pgf@y}
+% \end{macrocode}
+% If we're dealing with filaments, we can get false positives from the end points.
+% \begin{macrocode}
+ \bool_set_false:N \l__knot_skip_bool
+ \bool_if:NT \l__knot_self_intersections_bool
+ {
+% \end{macrocode}
+% If one filament preceded the other, test for the intersection being at the relevant end point.
+% \begin{macrocode}
+ \tl_set:Nn \l_tmpa_tl {knot previous}
+ \tl_put_right:NV \l_tmpa_tl \l__knot_tmpa_tl
+ \tl_set:Nv \l_tmpa_tl \l_tmpa_tl
+ \tl_if_eq:NNT \l_tmpa_tl \l__knot_tmpb_tl
+ {
+ \knot_test_endpoint:VnT \l__knot_tmpb_tl {final point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ }
+
+ \tl_set:Nn \l_tmpa_tl {knot previous}
+ \tl_put_right:NV \l_tmpa_tl \l__knot_tmpb_tl
+ \tl_set:Nv \l_tmpa_tl \l_tmpa_tl
+ \tl_if_eq:NNT \l_tmpa_tl \l__knot_tmpa_tl
+ {
+ \knot_test_endpoint:VnT \l__knot_tmpa_tl {final point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ }
+ }
+% \end{macrocode}
+% The can also say that end points of filaments (or strands) should simply be ignored anyway.
+% \begin{macrocode}
+ \bool_if:NT \l__knot_ignore_ends_bool
+ {
+ \knot_test_endpoint:VnT \l__knot_tmpa_tl {initial point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ \knot_test_endpoint:VnT \l__knot_tmpa_tl {final point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ \knot_test_endpoint:VnT \l__knot_tmpb_tl {initial point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ \knot_test_endpoint:VnT \l__knot_tmpb_tl {final point}
+ {
+ \bool_set_true:N \l__knot_skip_bool
+ }
+ }
+% \end{macrocode}
+% Assuming that we passed all the above tests, we render the crossing.
+% \begin{macrocode}
+ \bool_if:NF \l__knot_skip_bool
+ {
+
+ \int_gincr:N \l__knot_intersections_int
+% \end{macrocode}
+% This is the flip test.
+% We only render one of the paths.
+% The ``flip'' swaps which one we render.
+% \begin{macrocode}
+ \bool_if:nTF
+ {
+ \tl_if_exist_p:c {l__knot_crossing_ \int_use:N
+ \l__knot_intersections_int}
+ &&
+ ! \tl_if_empty_p:c {l__knot_crossing_ \int_use:N
+ \l__knot_intersections_int}
+ }
+ {
+ \tl_set_eq:NN \l__knot_tmpg_tl \l__knot_tmpb_tl
+ }
+ {
+ \tl_set_eq:NN \l__knot_tmpg_tl \l__knot_tmpa_tl
+ }
+% \end{macrocode}
+% Now we know which one we're rendering, we test to see if we should also render its predecessor or successor to ensure that we render a path through the entire crossing region.
+% \begin{macrocode}
+ \bool_if:NT \l__knot_self_intersections_bool
+ {
+ \knot_test_endpoint:VnT \l__knot_tmpg_tl {initial point}
+ {
+ \bool_set_true:N \l__knot_prepend_prev_bool
+ }
+ {
+ \bool_set_false:N \l__knot_prepend_prev_bool
+ }
+
+ \knot_test_endpoint:VnT \l__knot_tmpg_tl {final point}
+ {
+ \bool_set_true:N \l__knot_append_next_bool
+ }
+ {
+ \bool_set_false:N \l__knot_append_next_bool
+ }
+% \end{macrocode}
+% If either of those tests succeeded, do the appending or prepending.
+% \begin{macrocode}
+ \bool_if:nT
+ {
+ \l__knot_prepend_prev_bool || \l__knot_append_next_bool
+ }
+ {
+ \spath_clone:nn {knot \tl_use:N \l__knot_tmpg_tl}
+ {knot \tl_use:N \l__knot_prefix_tl -1}
+
+ \tl_set_eq:cc {l__knot_options_ \tl_use:N \l__knot_prefix_tl -1} {l__knot_options_ \tl_use:N \l__knot_tmpg_tl}
+
+ \bool_if:NT \l__knot_prepend_prev_bool
+ {
+ \spath_prepend_no_move:nn {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}}
+% \end{macrocode}
+% If we split potentially self intersecting curves, we test to see if we should prepend yet another segment.
+% \begin{macrocode}
+ \bool_if:NT \l__knot_splits_bool
+ {
+ \knot_test_endpoint:vnT {knot previous \tl_use:N \l__knot_tmpg_tl} {initial point}
+ {
+ \spath_get:nnN {knot \tl_use:N \l__knot_prefix_tl -1} {path} \l_tmpa_tl
+ \spath_prepend_no_move:nn {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:c {knot previous \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}}}
+ \spath_get:nnN {knot \tl_use:N \l__knot_prefix_tl -1} {path} \l_tmpa_tl
+
+ }
+ }
+ }
+% \end{macrocode}
+% Now the same for appending.
+% \begin{macrocode}
+ \bool_if:NT \l__knot_append_next_bool
+ {
+ \spath_append_no_move:nn {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:c {knot next \tl_use:N \l__knot_tmpg_tl}}
+ \bool_if:NT \l__knot_splits_bool
+ {
+ \knot_test_endpoint:vnT {knot previous \tl_use:N \l__knot_tmpg_tl} {final point}
+ {
+ \spath_append_no_move:nn {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:c {knot next \tl_use:c {knot next \tl_use:N \l__knot_tmpg_tl}}}
+
+ }
+ }
+ }
+
+ \tl_set:Nn \l__knot_tmpg_tl {\tl_use:N \l__knot_prefix_tl -1}
+ }
+ }
+% \end{macrocode}
+% Now we render the crossing.
+% \begin{macrocode}
+ \group_begin:
+ \tikzset{knot~ diagram/intersection~ \int_use:N \l__knot_intersections_int/.try}
+ \knot_draw_crossing:nVV {\tl_use:N \l__knot_tmpg_tl} \l__knot_tmpa_dim \l__knot_tmpb_dim
+ \group_end:
+% \end{macrocode}
+% And stick a coordinate possibly with a label at the crossing.
+% \begin{macrocode}
+ \tl_use:N \l__knot_node_tl (\l__knot_name_tl \c_space_tl \int_use:N \l__knot_intersections_int) at (\l__knot_tmpa_dim, \l__knot_tmpb_dim) {};
+ }
+}
+
+\cs_generate_variant:Nn \knot_intersections:nn {VV}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_test_endpoint:N}
+% Test whether the point is near the intersection point.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \knot_test_endpoint:N #1 {p,T,F,TF}
+{
+ \dim_compare:nTF
+ {
+ \dim_abs:n {\pgf@x - \tl_item:Nn #1 {1}}
+ +
+ \dim_abs:n {\pgf@y - \tl_item:Nn #1 {2}}
+ <
+ \l__knot_tolerance_dim
+ }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_test_endpoint:nn}
+% Wrapper around the above.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \knot_test_endpoint:nn #1#2 {T,F,TF}
+{
+ \spath_get:nnN {knot #1} {#2} \l__knot_tmpd_tl
+ \knot_test_endpoint:NTF \l__knot_tmpd_tl
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+}
+
+\cs_generate_variant:Nn \knot_test_endpoint:nnT {VnT,vnT}
+\cs_generate_variant:Nn \knot_test_endpoint:nnF {VnF,vnF}
+\cs_generate_variant:Nn \knot_test_endpoint:nnTF {VnTF,vnTF}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_draw_crossing:nnn}
+% This is the code that actually renders a crossing.
+% \begin{macrocode}
+\cs_new_nopar:Npn \knot_draw_crossing:nnn #1#2#3
+{
+ \group_begin:
+ \pgfscope
+ \clip (#2, #3) circle[radius=\l__knot_clip_radius_dim];
+
+ \tl_set:Nn \l_tmpa_tl {knot~ diagram/every~ strand/.try,}
+ \tl_if_exist:cT {l__knot_options_ #1}
+ {
+ \tl_put_right:Nv \l_tmpa_tl {l__knot_options_ #1}
+ }
+ \tl_put_right:Nn \l_tmpa_tl {,knotbg,line~ width= \tl_use:N \l__knot_clip_width_tl * \pgflinewidth}
+ \spath_tikz_path:Vn \l_tmpa_tl {knot #1}
+
+ \endpgfscope
+
+ \pgfscope
+ \clip (#2, #3) circle[radius=1.1\l__knot_clip_radius_dim];
+
+ \tl_set:Nn \l_tmpa_tl {knot~ diagram/every~ strand/.try,}
+ \tl_if_exist:cT {l__knot_options_ #1}
+ {
+ \tl_put_right:Nv \l_tmpa_tl {l__knot_options_ #1}
+ }
+ \tl_put_right:Nn \l_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try}
+ \spath_tikz_path:Vn \l_tmpa_tl {knot #1}
+
+ \endpgfscope
+ \group_end:
+}
+
+\cs_generate_variant:Nn \knot_draw_crossing:nnn {nVV}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_split_strands:}
+% This, and the following macros, are for splitting strands into filaments.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_split_strands:
+{
+ \int_gzero:N \l__knot_filaments_int
+ \int_step_function:nnnN {1} {1} {\l__knot_strands_int} \knot_split_strand:n
+ \int_step_function:nnnN {1} {1} {\l__knot_filaments_int} \knot_compute_nexts:n
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_compute_nexts:n}
+% Each filament needs to know its predecessor and successor.
+% We work out the predecessors as we go along, this fills in the successors.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_compute_nexts:n #1
+{
+ \tl_clear_new:c {knot next \tl_use:c {knot previous filament #1}}
+ \tl_set:cn {knot next \tl_use:c {knot previous filament #1}} {filament #1}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_split_strand:n}
+% Sets up the split for a single strand.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_split_strand:n #1
+{
+ \int_set_eq:NN \l__knot_component_start_int \l__knot_filaments_int
+ \int_incr:N \l__knot_component_start_int
+ \spath_map_segment_function:nN {knot strand #1} \knot_save_filament:NN
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\knot_save_filament:NN}
+% Saves a filament as a new \Verb+spath+ object.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \knot_save_filament:NN #1#2
+{
+ \tl_case:Nnn #1
+ {
+ \g__spath_moveto_tl
+ {
+ \int_compare:nT {\l__knot_component_start_int < \l__knot_filaments_int}
+ {
+ \int_set_eq:NN \l__knot_component_start_int \l__knot_filaments_int
+ }
+ }
+ \g__spath_lineto_tl
+ {
+ \int_gincr:N \l__knot_filaments_int
+ \spath_clear_new:n {knot filament \int_use:N \l__knot_filaments_int}
+ \spath_put:nnV {knot filament \int_use:N \l__knot_filaments_int} {path} #2
+ \tl_clear_new:c {knot previous filament \int_use:N \l__knot_filaments_int}
+ \int_compare:nF {\l__knot_component_start_int == \l__knot_filaments_int}
+ {
+ \tl_set:cx {knot previous filament \int_use:N \l__knot_filaments_int} {filament \int_eval:n {\l__knot_filaments_int - 1}}
+ }
+ }
+ \g__spath_curvetoa_tl
+ {
+ \int_gincr:N \l__knot_filaments_int
+ \spath_clear_new:n {knot filament \int_use:N \l__knot_filaments_int}
+ \spath_put:nnV {knot filament \int_use:N \l__knot_filaments_int} {path} #2
+ \tl_clear_new:c {knot previous filament \int_use:N \l__knot_filaments_int}
+ \int_compare:nF {\l__knot_component_start_int == \l__knot_filaments_int}
+ {
+ \tl_set:cx {knot previous filament \int_use:N \l__knot_filaments_int} {filament \int_eval:n {\l__knot_filaments_int - 1}}
+ }
+ }
+ \g__spath_close_tl
+ {
+ \int_gincr:N \l__knot_filaments_int
+ \spath_clear_new:n {knot filament \int_use:N \l__knot_filaments_int}
+ \tl_set_eq:NN \l_tmpa_tl #2
+ \tl_set:Nx \l_tmpa_tl {\tl_item:Nn #2 {1}\tl_item:Nn #2 {2}\tl_item:Nn #2 {3}}
+ \tl_put_right:NV \l_tmpa_tl \g__spath_lineto_tl
+ \tl_set:Nx \l_tmpa_tl {\tl_item:Nn #2 {5}\tl_item:Nn #2 {6}}
+ \spath_put:nnV {knot filament \int_use:N \l__knot_filaments_int} {path} \l_tmpa_tl
+ \tl_clear_new:c {knot previous filament \int_use:N \l__knot_filaments_int}
+ \int_compare:nF {\l__knot_component_start_int == \l__knot_filaments_int}
+ {
+ \tl_set:cx {knot previous filament \int_use:N \l__knot_filaments_int} {filament \int_eval:n {\l__knot_filaments_int - 1}}
+ }
+ \tl_set:cx {knot previous filament \int_use:N \l__knot_component_start_int} {filament \int_use:N \l__knot_filaments_int}
+ }
+ }
+ {
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\redraw}
+% The user can redraw segments of the strands at specific locations.
+% \begin{macrocode}
+\NewDocumentCommand \redraw { m m }
+{
+ \tikz@scan@one@point\pgfutil@firstofone #2 \relax
+ \tl_put_right:Nn \l__knot_redraws_tl {\knot_draw_crossing:nnn}
+ \tl_put_right:Nx \l__knot_redraws_tl {
+ {strand #1} {\dim_use:N \pgf@x} {\dim_use:N \pgf@y}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+% \begin{macro}{\pgf@sh@@knotanchor}
+% Add the extra anchors for the knot crossing nodes.
+% \begin{macrocode}
+\def\pgf@sh@@knotanchor#1#2{%
+ \anchor{#2 north west}{%
+ \csname pgf@anchor@knot #1@north west\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 north east}{%
+ \csname pgf@anchor@knot #1@north east\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 south west}{%
+ \csname pgf@anchor@knot #1@south west\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 south east}{%
+ \csname pgf@anchor@knot #1@south east\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 north}{%
+ \csname pgf@anchor@knot #1@north\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 east}{%
+ \csname pgf@anchor@knot #1@east\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 west}{%
+ \csname pgf@anchor@knot #1@west\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+ \anchor{#2 south}{%
+ \csname pgf@anchor@knot #1@south\endcsname%
+ \pgf@x=#2\pgf@x%
+ \pgf@y=#2\pgf@y%
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot crossing}
+% \begin{macrocode}
+\pgfdeclareshape{knot crossing}
+{
+ \inheritsavedanchors[from=circle] % this is nearly a circle
+ \inheritanchorborder[from=circle]
+ \inheritanchor[from=circle]{north}
+ \inheritanchor[from=circle]{north west}
+ \inheritanchor[from=circle]{north east}
+ \inheritanchor[from=circle]{center}
+ \inheritanchor[from=circle]{west}
+ \inheritanchor[from=circle]{east}
+ \inheritanchor[from=circle]{mid}
+ \inheritanchor[from=circle]{mid west}
+ \inheritanchor[from=circle]{mid east}
+ \inheritanchor[from=circle]{base}
+ \inheritanchor[from=circle]{base west}
+ \inheritanchor[from=circle]{base east}
+ \inheritanchor[from=circle]{south}
+ \inheritanchor[from=circle]{south west}
+ \inheritanchor[from=circle]{south east}
+ \inheritanchorborder[from=circle]
+ \pgf@sh@@knotanchor{crossing}{2}
+ \pgf@sh@@knotanchor{crossing}{3}
+ \pgf@sh@@knotanchor{crossing}{4}
+ \pgf@sh@@knotanchor{crossing}{8}
+ \pgf@sh@@knotanchor{crossing}{16}
+ \pgf@sh@@knotanchor{crossing}{32}
+ \backgroundpath{
+ \pgfutil@tempdima=\radius%
+ \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
+ \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
+ \ifdim\pgf@xb<\pgf@yb%
+ \advance\pgfutil@tempdima by-\pgf@yb%
+ \else%
+ \advance\pgfutil@tempdima by-\pgf@xb%
+ \fi%
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot over cross}
+% \begin{macrocode}
+\pgfdeclareshape{knot over cross}
+{
+ \inheritsavedanchors[from=rectangle] % this is nearly a circle
+ \inheritanchorborder[from=rectangle]
+ \inheritanchor[from=rectangle]{north}
+ \inheritanchor[from=rectangle]{north west}
+ \inheritanchor[from=rectangle]{north east}
+ \inheritanchor[from=rectangle]{center}
+ \inheritanchor[from=rectangle]{west}
+ \inheritanchor[from=rectangle]{east}
+ \inheritanchor[from=rectangle]{mid}
+ \inheritanchor[from=rectangle]{mid west}
+ \inheritanchor[from=rectangle]{mid east}
+ \inheritanchor[from=rectangle]{base}
+ \inheritanchor[from=rectangle]{base west}
+ \inheritanchor[from=rectangle]{base east}
+ \inheritanchor[from=rectangle]{south}
+ \inheritanchor[from=rectangle]{south west}
+ \inheritanchor[from=rectangle]{south east}
+ \inheritanchorborder[from=rectangle]
+ \backgroundpath{
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
+ }
+ \foregroundpath{
+% store lower right in xa/ya and upper right in xb/yb
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot under cross}
+% \begin{macrocode}
+\pgfdeclareshape{knot under cross}
+{
+ \inheritsavedanchors[from=rectangle] % this is nearly a circle
+ \inheritanchorborder[from=rectangle]
+ \inheritanchor[from=rectangle]{north}
+ \inheritanchor[from=rectangle]{north west}
+ \inheritanchor[from=rectangle]{north east}
+ \inheritanchor[from=rectangle]{center}
+ \inheritanchor[from=rectangle]{west}
+ \inheritanchor[from=rectangle]{east}
+ \inheritanchor[from=rectangle]{mid}
+ \inheritanchor[from=rectangle]{mid west}
+ \inheritanchor[from=rectangle]{mid east}
+ \inheritanchor[from=rectangle]{base}
+ \inheritanchor[from=rectangle]{base west}
+ \inheritanchor[from=rectangle]{base east}
+ \inheritanchor[from=rectangle]{south}
+ \inheritanchor[from=rectangle]{south west}
+ \inheritanchor[from=rectangle]{south east}
+ \inheritanchorborder[from=rectangle]
+ \backgroundpath{
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
+ }
+ \foregroundpath{
+% store lower right in xa/ya and upper right in xb/yb
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot vert}
+% \begin{macrocode}
+\pgfdeclareshape{knot vert}
+{
+ \inheritsavedanchors[from=rectangle] % this is nearly a circle
+ \inheritanchorborder[from=rectangle]
+ \inheritanchor[from=rectangle]{north}
+ \inheritanchor[from=rectangle]{north west}
+ \inheritanchor[from=rectangle]{north east}
+ \inheritanchor[from=rectangle]{center}
+ \inheritanchor[from=rectangle]{west}
+ \inheritanchor[from=rectangle]{east}
+ \inheritanchor[from=rectangle]{mid}
+ \inheritanchor[from=rectangle]{mid west}
+ \inheritanchor[from=rectangle]{mid east}
+ \inheritanchor[from=rectangle]{base}
+ \inheritanchor[from=rectangle]{base west}
+ \inheritanchor[from=rectangle]{base east}
+ \inheritanchor[from=rectangle]{south}
+ \inheritanchor[from=rectangle]{south west}
+ \inheritanchor[from=rectangle]{south east}
+ \inheritanchorborder[from=rectangle]
+ \backgroundpath{
+% store lower right in xa/ya and upper right in xb/yb
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
+ \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{knot horiz}
+% \begin{macrocode}
+\pgfdeclareshape{knot horiz}
+{
+ \inheritsavedanchors[from=rectangle] % this is nearly a circle
+ \inheritanchorborder[from=rectangle]
+ \inheritanchor[from=rectangle]{north}
+ \inheritanchor[from=rectangle]{north west}
+ \inheritanchor[from=rectangle]{north east}
+ \inheritanchor[from=rectangle]{center}
+ \inheritanchor[from=rectangle]{west}
+ \inheritanchor[from=rectangle]{east}
+ \inheritanchor[from=rectangle]{mid}
+ \inheritanchor[from=rectangle]{mid west}
+ \inheritanchor[from=rectangle]{mid east}
+ \inheritanchor[from=rectangle]{base}
+ \inheritanchor[from=rectangle]{base west}
+ \inheritanchor[from=rectangle]{base east}
+ \inheritanchor[from=rectangle]{south}
+ \inheritanchor[from=rectangle]{south west}
+ \inheritanchor[from=rectangle]{south east}
+ \inheritanchorborder[from=rectangle]
+ \foregroundpath{
+% store lower right in xa/ya and upper right in xb/yb
+ \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
+ \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
+ \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
+ \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \iffalse
+%</knots>
+% \fi
+%\Finale
+\endinput
diff --git a/Master/texmf-dist/source/latex/spath3/spath3.ins b/Master/texmf-dist/source/latex/spath3/spath3.ins
new file mode 100644
index 00000000000..b2836135ac1
--- /dev/null
+++ b/Master/texmf-dist/source/latex/spath3/spath3.ins
@@ -0,0 +1,91 @@
+%%
+%% This is file `spath3.ins',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% spath3.dtx (with options: `install')
+%% ----------------------------------------------------------------
+%% spath3 --- Functions for manipulating PGF soft paths
+%% E-mail: stacey@math.ntnu.no
+%% Released under the LaTeX Project Public License v1.3c or later
+%% See http://www.latex-project.org/lppl.txt
+%% ----------------------------------------------------------------
+%%
+\input docstrip.tex
+\keepsilent
+\askforoverwritefalse
+\preamble
+----------------------------------------------------------------
+spath3 --- Functions for manipulating PGF soft paths
+E-mail: stacey@math.ntnu.no
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+----------------------------------------------------------------
+
+\endpreamble
+\postamble
+
+Copyright (C) 2011 by Andrew Stacey <stacey@math.ntnu.no>
+
+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 spath3.dtx
+ calligraphy_doc.tex
+ knot_doc.tex
+and the derived files spath3.ins,
+ spath3.pdf,
+ spath3.sty,
+ tikzlibrarycalligraphy.code.tex
+ tikzlibraryknots.code.tex
+ calligraphy_doc.pdf
+ knots_doc.pdf
+ README.txt
+
+\endpostamble
+\usedir{tex/latex/spath3}
+\generate{
+ \file{\jobname.sty}{\from{\jobname.dtx}{spath3}}
+}
+\generate{
+ \file{tikzlibrarycalligraphy.code.tex}{\from{\jobname.dtx}{calligraphy}}
+}
+\generate{
+ \file{tikzlibraryknots.code.tex}{\from{\jobname.dtx}{knots}}
+}
+\endbatchfile
+%%
+%% Copyright (C) 2011 by Andrew Stacey <stacey@math.ntnu.no>
+%%
+%% 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 spath3.dtx
+%% calligraphy_doc.tex
+%% knot_doc.tex
+%% and the derived files spath3.ins,
+%% spath3.pdf,
+%% spath3.sty,
+%% tikzlibrarycalligraphy.code.tex
+%% tikzlibraryknots.code.tex
+%% calligraphy_doc.pdf
+%% knots_doc.pdf
+%% README.txt
+%%
+%%
+%% End of file `spath3.ins'.