diff options
author | Karl Berry <karl@freefriends.org> | 2021-01-23 22:17:41 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-01-23 22:17:41 +0000 |
commit | 3fc4de03f2da103a96f5d0cc757300f8c7e311f1 (patch) | |
tree | 69271c9383f64bb9905fa1e00910cf2b18c96119 /Master/texmf-dist | |
parent | 03a1a8f6b693dc58a1840c8703af5c5399dc6117 (diff) |
spath3 (23jan21)
git-svn-id: svn://tug.org/texlive/trunk@57504 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
18 files changed, 11052 insertions, 5703 deletions
diff --git a/Master/texmf-dist/doc/latex/spath3/README b/Master/texmf-dist/doc/latex/spath3/README index a9d1fe62103..dad3e28a92f 100644 --- a/Master/texmf-dist/doc/latex/spath3/README +++ b/Master/texmf-dist/doc/latex/spath3/README @@ -1,6 +1,6 @@ ---------------------------------------------------------------- spath3 --- LaTeX3 functions for manipulating PGF soft paths -E-mail: stacey@math.ntnu.no +E-mail: loopspace@mathforge.org Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt ---------------------------------------------------------------- diff --git a/Master/texmf-dist/doc/latex/spath3/README.txt b/Master/texmf-dist/doc/latex/spath3/README.txt index a9d1fe62103..dad3e28a92f 100644 --- a/Master/texmf-dist/doc/latex/spath3/README.txt +++ b/Master/texmf-dist/doc/latex/spath3/README.txt @@ -1,6 +1,6 @@ ---------------------------------------------------------------- spath3 --- LaTeX3 functions for manipulating PGF soft paths -E-mail: stacey@math.ntnu.no +E-mail: loopspace@mathforge.org Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt ---------------------------------------------------------------- diff --git a/Master/texmf-dist/doc/latex/spath3/calligraphy.pdf b/Master/texmf-dist/doc/latex/spath3/calligraphy.pdf Binary files differnew file mode 100644 index 00000000000..f2852f4d1ba --- /dev/null +++ b/Master/texmf-dist/doc/latex/spath3/calligraphy.pdf diff --git a/Master/texmf-dist/doc/latex/spath3/calligraphy_doc.tex b/Master/texmf-dist/doc/latex/spath3/calligraphy.tex index c1b88c9e8e7..7690e5c5b73 100644 --- a/Master/texmf-dist/doc/latex/spath3/calligraphy_doc.tex +++ b/Master/texmf-dist/doc/latex/spath3/calligraphy.tex @@ -1,4 +1,4 @@ -\immediate\write18{tex spath3.dtx} +\immediate\write18{tex spath3_doc.dtx} \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{trace} @@ -11,7 +11,14 @@ \usepackage{listings} \lstloadlanguages{[LaTeX]TeX} -\lstset{breakatwhitespace=true,breaklines=true,language=TeX} +\lstset{ + breakatwhitespace=true, + breaklines=true, + language=[LaTeX]TeX, + basicstyle=\small\ttfamily, + keepspaces=true, + columns=fullflexible +} \usepackage{fancyvrb} @@ -22,7 +29,6 @@ \begin{center} \setlength{\parindent}{0pt} \fbox{\begin{minipage}{.9\linewidth} - \lstset{breakatwhitespace=true,breaklines=true,language=TeX,basicstyle=\small} \lstinputlisting[]{example.out} \end{minipage}} @@ -36,13 +42,20 @@ \GetFileInfo{spath3.sty} \title{The \textsf{calligraphy} Package: Documentation} -\author{Andrew Stacey \\ \url{stacey@math.ntnu.no}} +\author{Andrew Stacey \\ \url{loopspace@mathforge.org}} \date{\fileversion~from \filedate} \begin{document} \maketitle -% \section{Introduction} + + \section{Pre-Introduction} + This library is built on top of a package for manipulating PGF's \emph{soft paths} called \texttt{spath3}. + Version 2.0 of \texttt{spath3} involved considerable reorganisation of the code. + I tried to ensure that this didn't affect this library but it is extremely likely that I wasn't fully successful. + If something that used to work no longer does, please do let me know either by opening an issue on github (\url{https://github.com/loopspace/spath3}) or at the above email. + + \section{Introduction} The \Verb+calligraphy+ TikZ library is designed to enable calligraphic style drawings in TikZ. The idea is to be able to ``stroke'' a line with a ``pen''. As a simple example, compare the two lines in the following picture. @@ -255,4 +268,4 @@ The following pens are predefined: \end{example} \end{itemize} -\end{document}
\ No newline at end of file +\end{document} diff --git a/Master/texmf-dist/doc/latex/spath3/calligraphy_doc.pdf b/Master/texmf-dist/doc/latex/spath3/calligraphy_doc.pdf Binary files differdeleted file mode 100644 index 12a0313d8ad..00000000000 --- a/Master/texmf-dist/doc/latex/spath3/calligraphy_doc.pdf +++ /dev/null diff --git a/Master/texmf-dist/doc/latex/spath3/knots.pdf b/Master/texmf-dist/doc/latex/spath3/knots.pdf Binary files differnew file mode 100644 index 00000000000..b1962a3c4c4 --- /dev/null +++ b/Master/texmf-dist/doc/latex/spath3/knots.pdf diff --git a/Master/texmf-dist/doc/latex/spath3/knots_doc.tex b/Master/texmf-dist/doc/latex/spath3/knots.tex index 67c23ca1287..20859a1d4ec 100644 --- a/Master/texmf-dist/doc/latex/spath3/knots_doc.tex +++ b/Master/texmf-dist/doc/latex/spath3/knots.tex @@ -1,17 +1,24 @@ -\immediate\write18{tex spath3.dtx} +\immediate\write18{tex spath3_code.dtx} \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{trace} \usepackage{lmodern} \usepackage{morefloats} \usepackage{tikz} -\usetikzlibrary{knots} +\usetikzlibrary{knots,spath3,hobby} \usepackage[numbered]{hypdoc} \definecolor{lstbgcolor}{rgb}{0.9,0.9,0.9} \usepackage{listings} \lstloadlanguages{[LaTeX]TeX} -\lstset{breakatwhitespace=true,breaklines=true,language=TeX} +\lstset{ + breakatwhitespace=true, + breaklines=true, + language=[LaTeX]TeX, + basicstyle=\small\ttfamily, + keepspaces=true, + columns=fullflexible +} \usepackage{fancyvrb} @@ -22,7 +29,6 @@ \begin{center} \setlength{\parindent}{0pt} \fbox{\begin{minipage}{.9\linewidth} - \lstset{breakatwhitespace=true,breaklines=true,language=TeX,basicstyle=\small} \lstinputlisting[]{example.out} \end{minipage}} @@ -37,15 +43,41 @@ \GetFileInfo{spath3.sty} \title{The \textsf{knots} Package: Documentation} -\author{Andrew Stacey \\ \url{stacey@math.ntnu.no}} +\author{Andrew Stacey \\ \url{loopspace@mathforge.org}} \date{\fileversion~from \filedate} \begin{document} \maketitle -\section{Introduction} +\section{Pre-Introduction} + +This library is built on top of a package for manipulating PGF's \emph{soft paths} called \texttt{spath3}. + Version 2.0 of \texttt{spath3} involved considerable reorganisation of the code. + I tried to ensure that this didn't affect this library but it is extremely likely that I wasn't fully successful. + If something that used to work no longer does, please do let me know either by opening an issue on github (\url{https://github.com/loopspace/spath3}) or at the above email. + + That version of \texttt{spath3} also introduced an alternative way of drawing knots which involves breaking the paths at their crossing points and introducing actual gaps. + This makes it easier to do things like have the knots on non-uniform backgrounds, and to style different parts of the knot differently such as illustrating a \(3\)--colouring. + To see how that works, look at the documentation of the \texttt{spath3} TikZ library. + Here's an example of how to draw a knot with that library. + + \begin{example} +\begin{tikzpicture}[ + use Hobby shortcut, + every trefoil component/.style={ultra thick, draw}, + trefoil component 1/.style={red}, + trefoil component 2/.style={blue}, + trefoil component 3/.style={green}, +] +\path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); +\tikzset{spath/knot={trefoil}{8pt}{1,3,5}} +\end{tikzpicture} +\end{example} + +\section{Introduction} + The \Verb+knots+ package is a TikZ library for drawing knot (and similar) diagrams. It provides a few useful styles and node shapes but its main contribution is the \Verb+knot+ environment. The \Verb+knot+ environment allows you to draw some strands of a knot (or braid or tangle or whatever -- we shall use the imprecise term ``knot'' to refer to any similar diagram) and then to modify the crossings via a simple interface. diff --git a/Master/texmf-dist/doc/latex/spath3/knots_doc.pdf b/Master/texmf-dist/doc/latex/spath3/knots_doc.pdf Binary files differdeleted file mode 100644 index d818161e21f..00000000000 --- a/Master/texmf-dist/doc/latex/spath3/knots_doc.pdf +++ /dev/null diff --git a/Master/texmf-dist/doc/latex/spath3/spath3.pdf b/Master/texmf-dist/doc/latex/spath3/spath3.pdf Binary files differnew file mode 100644 index 00000000000..bbc90be42e4 --- /dev/null +++ b/Master/texmf-dist/doc/latex/spath3/spath3.pdf diff --git a/Master/texmf-dist/doc/latex/spath3/spath3.tex b/Master/texmf-dist/doc/latex/spath3/spath3.tex new file mode 100644 index 00000000000..86f925ba9e7 --- /dev/null +++ b/Master/texmf-dist/doc/latex/spath3/spath3.tex @@ -0,0 +1,650 @@ +\RequirePackage{shellesc} +\immediate\write18{tex spath3_code.dtx} +\documentclass{l3doc} +\usepackage{tikz} +\usetikzlibrary{ + spath3, + hobby, + patterns, + intersections, + arrows.meta, +} + +\usepackage{listings} +\lstloadlanguages{[LaTeX]TeX} +\lstset{ + breakatwhitespace=true, + breaklines=true, + language=[LaTeX]TeX, + basicstyle=\small\ttfamily, + keepspaces=true, + columns=fullflexible +} + +\usepackage{fancyvrb} + +\newenvironment{example} +{\VerbatimEnvironment +\begin{VerbatimOut}[gobble=0]{example.out}} +{\end{VerbatimOut} + \begin{center} + \setlength{\parindent}{0pt} + \fbox{\begin{minipage}{.9\linewidth} + \lstinputlisting[]{example.out} + \end{minipage}} + + \fbox{\begin{minipage}{.9\linewidth} + \centering + \input{example.out} + \end{minipage}} +\end{center} +} + +\providecommand*{\url}{\texttt} +\GetFileInfo{spath3.sty} + +\title{The \textsf{spath3} Package: Documentation} +\author{Andrew Stacey \\ \url{loopspace@mathforge.org}} + \date{\fileversion~from \filedate} + + \begin{document} + + \maketitle + + \section{Introduction} + + The \texttt{spath3} package was originally designed as a low-level package for manipulating the \emph{soft paths} defined by PGF/TikZ. + Soft paths form one stage of the stack of translations between what the author writes in the \texttt{tikzpicture} environments in their \LaTeX\ document and what is eventually written to the output file. + Most of the complicated processing has been done by the time a soft path is constructed, but it is still very definitely a \TeX\ object and there has not, for example, been any consideration as to what the eventual output file format is (such as PDF, DVI, or SVG). + So it is very amenable to being modified at this stage and this package provides a set of routines for doing so. + + The original purpose was to provide a common core on which other packages would be built. + Indeed, the packages \texttt{calligraphy}, \texttt{knots}, and \texttt{penrose} all use this package. + However, over time I've found myself wanting to use the routines of this package at a higher level and so have designed some user-level interfaces. + This document documents those. + + To clarify some terminology, paths are composed of \emph{segment} and \emph{components}. +A \emph{segment} is a minimal drawing piece. +Thus it might be a straight line or a B\'ezier curve. +A \emph{component} is a minimal connected section of the path. +So every component starts with a move command and continues until the next move command. +For ease of implementation (and to enable a copperplate pen in the calligraphy package!), an isolated move is considered as a component. + + + \section{TikZ Keys} + +\begin{lstlisting} +\usetikzlibrary{spath3} +\end{lstlisting} + +The \texttt{spath3} TikZ library defines a set of keys that can be issued to muck about with soft paths. +These are all defined in the \texttt{spath} family, so all the following keys should be prefixed by \texttt{spath/}, or the key \texttt{spath/.cd} needs to be used beforehand. + +\subsection{Saving and Using Soft Paths} + +\begin{function}{save} +\begin{syntax} +|save=|\meta{name} +\end{syntax} + +Saves the current path with name \texttt{<name>}. +This delays until the path is fully constructed so can be issued in the options to the main command. + +Soft paths constructed this way are local to the group in which the path command is issued. + +The soft path is actually stored in a macro constructed from the name. +There are a couple of reasons for using a \emph{name} rather than a macro directly. +One is so that it is compatible with the \texttt{intersections} library -- by default both this package and that save their paths in the same underlying macro. +The other is to provide a way to link a soft path with a set of TikZ styles (this is particularly useful when splitting the path into components). +\end{function} + +\begin{function}{save global} +\begin{syntax} +|save global=|\meta{name} +\end{syntax} + +Saves the current soft path globally. +\end{function} + +\begin{function}{clone} +\begin{syntax} +|clone=|\marg{target}\marg{source} +\end{syntax} + +Clones one soft path into another. +\end{function} + +\begin{function}{restore} +\begin{syntax} +|restore=|\meta{name} +\end{syntax} + +Restores a previously saved soft path to the current path. +This happens immediately so can be issued in the options to the main command and then the path can be extended with normal drawing commands. +Any keys that affect the soft path directly should be applied \emph{before} this one. + +One thing should be noted about transformations. +By the time a soft path is built, all available transformations have been applied. +This means that when re-inserting a soft path back into a high level command (such as |\draw|), the effect of existing transformations might produce some confusing effects. +When restoring a path then the library tries to set the last point correctly, but depending on how this is used it can result in transformations being applied twice. +\end{function} + +\begin{function}{append} +\begin{syntax} +|append=|\meta{name} +\end{syntax} + +This inserts a soft path into the path at the current point, it is therefore more suited to being used part way through a path construction. +In a sense, it is a little like a \texttt{pic} in that it enables the user to construct a path segment early to be reused at various places. + +The path is \emph{welded} on to the current path, meaning that it starts from the current point and there is no \texttt{move}. +This is particularly useful for creating filled regions. +\end{function} + +\begin{function}{reverse} +\begin{syntax} +|reverse=|\meta{name} +\end{syntax} + +Reverses the path in the named spath object. +This doesn't do any actually drawing. +The effect is local, but if you want to work with both the original path and its reversal in the same path then use the \texttt{clone} key to copy it first. +\end{function} + +\begin{function}{append reverse} +\begin{syntax} +|append reverse=|\meta{name} +\end{syntax} + +Like \texttt{append} except that the inserted path is reversed first. +\end{function} + +\begin{function}{insert} +\begin{syntax} +|insert=|\meta{name} +\end{syntax} + +Like \texttt{append} except that it doesn't move the inserted path and there is a move between the current path and the inserted path. +\end{function} + +\begin{function}{ + shorten at end, +shorten at start, +shorten at both ends +} +\begin{syntax} +|shorten at end=|\marg{name}\marg{dimen} +\end{syntax} + +Shortens the soft path by the dimension from one or both ends. +This shortens the soft path along its length so that it is guaranteed that the shorter path traces a subset of the original path. +For B\'ezier curves, however, the amount of shortening is approximate and is better for shorter distances. +If wanting to shorten by a large amount it is better to shorten by a small amount a number of times. +\end{function} + +\begin{function}{translate} +\begin{syntax} +|translate=|\marg{name}\marg{x-dimen}\marg{y-dimen} +\end{syntax} + +Translates the soft path by the given dimensions. +\end{function} + +\begin{function}{transform} +\begin{syntax} +|transform=|\marg{name}\marg{transformations} +\end{syntax} + +This applies the transformation to the soft path. +The transformation is processed by TikZ so should consist of TikZ-level transformations such as |shift={(2,2)}|. +\end{function} + +\subsection{Intersection Routines} + +To use these features you need to use the \texttt{intersections} library. + +\begin{function}{split at self intersections} +\begin{syntax} +|split at self intersections=|\meta{path} +\end{syntax} + +This inserts breaks into the named soft path at the points where it intersects itself. +\end{function} + +\begin{function}{split at intersections} +\begin{syntax} +|split at intersections=|\marg{first}\marg{second} +\end{syntax} + +This inserts breaks into a pair of paths at their mutual intersections. +\end{function} + +\subsection{Working with Components} + +\begin{function}{get components of} +\begin{syntax} +|get components of=|\marg{macro}\marg{path} +\end{syntax} + +This splits the path into a list of its components, which are stored in the macro. +The macro can be used in a |\foreach|. +\end{function} + +\begin{function}{render components} +\begin{syntax} +|render components=|\meta{path} +\end{syntax} + +This renders the components of a given path as separate TikZ commands, so that each can be separately styled. +It applies the following styles (in this order): + +\begin{enumerate} +\item \texttt{every spath component} +\item \texttt{spath component <number>} +\item \texttt{spath component=<number>} +\item \texttt{every <path> component} +\item \texttt{<path> component <number>} +\item \texttt{<path> component=<number>} +\end{enumerate} +\end{function} + +\begin{function}{insert gaps after components} +\begin{syntax} +|insert gaps after components=|\marg{path}\marg{gap}\marg{components} +\end{syntax} + +This inserts a gap between components of a path by shortening the end of the specified component and start of the next one. +The list of components is passed through a |\foreach| loop so that syntax like |2,4,...,16|. +\end{function} + +\begin{function}{join components} +\begin{syntax} +|join components=|\marg{path}\marg{components} +\end{syntax} + +This removes the \texttt{move} between the given component and the previous one. +If the component is the first one then it is joined to the last component. +\end{function} + +\begin{function}{spot weld} +\begin{syntax} +|spot weld=|\meta{path} +\end{syntax} + +This removes the \texttt{move} between any two components of the path where the end point of one component is the same as the initial point of the next (the tolerance on error here is \(0.01\)pt). +\end{function} + +\begin{function}{remove empty components} +\begin{syntax} +|remove empty components=|\meta{path} +\end{syntax} + +This removes empty components of the path (which consist of simply a move). +\end{function} + +\subsection{Shortening Paths} + +\begin{function}{ +shorten path at end, +shorten path at start, +shorten path at both ends +} +\begin{syntax} +|shorten path at end=|\marg{path}\marg{length} +\end{syntax} + +This shortens a path by the given amount from the specified end. +The shortening is done so that it guarantees that it lies along the original path, but therefore the length is not completely guaranteed to be accurate. +This is particularly true for B\'ezier paths and if there is a very short segment at the end. + +It uses the derivative at the end to work out how much to shorten by. +\end{function} + +\subsection{Exporting Paths} + +There are two keys to export a path. + +\begin{function}{save to aux} +\begin{syntax} +|save to aux=|\meta{path} +\end{syntax} + +This will save the path to the auxfile so that it is available again on the next run through. +\end{function} + +\begin{function}{export to svg} +\begin{syntax} +|export to svg=|\meta{path} +\end{syntax} + +Saves the path to the file \texttt{path.svg} as an SVG document. +\end{function} + +\subsection{Knots} + +\begin{function}{knot} +\begin{syntax} +|knot=|\meta{path}\meta{gap}\meta{components} +\end{syntax} + +This style combines various of the above to make it simpler to draw knots and links. +It expands to: + +\begin{lstlisting} +knot/.style n args={3}{ + spath/.cd, + split at self intersections=#1, + insert gaps after components={#1}{#2}{#3}, + maybe spot weld=#1, + render components=#1 +} +\end{lstlisting} + +This splits a path at the points where it self-intersects and then inserts gaps between specified components. +The key |maybe spot weld| does a |spot weld| depending on whether or not the key |draft mode| is set to |true| or |false|. +The point here is that when designing the knot it is useful to not weld together components since that changes the component count. +But once the gaps are inserted in the desired places, welding the remaining components produces a nicer diagram. + +The components can be styled using the keys as described in |render components|. +\end{function} + +\subsection{Coordinates} + +Soft paths are not natural TikZ objects and so when replaced back into a TikZ path construction then they don't fully interact with other TikZ things, like placing nodes at points on the path. +To make things a little easier there is defined a coordinate system which identifies a point at a certain location along a soft path and keys which apply a transformation. + +\begin{function}{spath cs} +\begin{syntax} +|(spath cs:|\marg{name} \marg{parameter}|)| +\end{syntax} + +The location specification is a little technical. +It is specified as a number from \(0\) to \(1\), but the parameter works as follows. +Let \(n\) be the number of \emph{segments} on the path (these are the individual drawing elements that make up the path). +The interval from \(\frac{k-1}{n}\) to \(\frac{k}{n}\) is assigned to the \(k\)th segment of the path. +Then for a parameter in that interval, the location uses the natural parametrisation of that segment. +For a straight line, it is simply the proportional position along but for a B\'ezier curve then it uses the B\'ezier parametrisation. + +The space is vital, so if the \texttt{name} is contained in a macro then a space has to be inserted somehow. +One option is to wrap the macro in braces, as seen in the examples in the next section. +\end{function} + +\begin{function}{transform to, upright transform to} +\begin{syntax} +|transform to=|\marg{path}\marg{parameter} +|upright transform to=|\marg{path}\marg{parameter} +\end{syntax} + +These keys (which are in the |spath| family) set the transformation so that the origin is at the specified point of the curve (as described above) and the \(x\)--axis is tangential to the curve. +The transformation is \emph{orthogonal} in that it is achieved by a rotation and a translation. + +The first key aligns the axes so that the \(x\)--axis is in the forward direction of the path as that path was constructed. +The second key aligns the axes so that the \(y\)--axis points up the page. +The intention with the second key is that it is similar to what happens with the |sloped| key when a node is placed on a curve. +\end{function} + +\section{Examples} + +\begin{enumerate} +\item Saving, restoring, inserting, and appending. + +\begin{example} +\begin{tikzpicture} +\path[spath/save=rpath] (0,0) to[out=30,in=150] (1,1); +\foreach \k in {1,...,9} { + \fill[green] (spath cs:rpath 0.\k) circle[radius=3pt]; + \node[above left] at (spath cs:rpath 0.\k) {\(0.\k\)}; +} +\fill[green] (2,2) circle[radius=3pt]; +\draw[blue, spath/transform={rpath}{shift={(2,2)}}, spath/restore=rpath] node[right] {transform}; +\draw[orange] (3,0) [spath/insert=rpath] node[right] {insert}; +\draw[red] (3,-1) -- +(0,2) [spath/append=rpath] node[above] {append}; +\draw[spath/restore=rpath] node[right] {restore}; +\end{tikzpicture} +\end{example} + +\item Reversing. + +\begin{example} +\begin{tikzpicture} +\path[spath/save=apath] (0,0) to[out=0,in=180] (2,1) to[out=0,in=180] (4,0); +\filldraw[ + green, + draw=black, + ultra thick, + spath/restore=apath +] -- ++(0,-4) [spath/append reverse=apath] -- cycle; +\end{tikzpicture} +\end{example} + +\item Transformations. + +\begin{example} +\begin{tikzpicture} +\draw[spath/save=tpath] (0,0) rectangle +(1,1); +\draw[rotate=45, xscale=2, yscale=3, ultra thick, red] (0,0) rectangle +(1,1); +\draw[ + spath/transform={tpath}{rotate=45, xscale=2, yscale=3}, + spath/restore={tpath}]; +\end{tikzpicture} +\end{example} + +\begin{example} +\begin{tikzpicture} +\draw[spath/save=oval] (0,0) to[out=0,in=0] (0,2) to[out=180,in=180] (0,0); +\foreach \k in {0,...,9} { + \node[transform shape, spath/transform to={oval}{0.\k}] {k}; +} +\begin{scope}[xshift = 3cm] +\draw[spath/save=soval] (0,0) to[out=0,in=0] (0,2) to[out=180,in=180] (0,0); +\foreach \k in {0,...,9} { + \node[transform shape, spath/upright transform to={soval}{0.\k}] {k}; +} +\end{scope} +\end{tikzpicture} +\end{example} + +\item Shortening. + +\begin{example} +\begin{tikzpicture} +\path[spath/save=apath] (0,0) foreach \k in {1,...,4} { -- ++(1,0) +(0,0)}; +\draw[ + ultra thick, + red, + spath/.cd, + shorten at end={apath}{7pt}, + shorten at start={apath}{9pt}, + translate={apath}{0pt}{1pt}, + restore=apath, +]; +\draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt]; +\end{tikzpicture} +\end{example} + + +\begin{example} +\begin{tikzpicture} +\path[spath/save=apath] (0,0) foreach \k in {1,...,4} { to[out=0,in=180] ++(1,0) +(0,0)}; +\draw[ + ultra thick, + red, + spath/.cd, + shorten at end={apath}{7pt}, + shorten at start={apath}{9pt}, + translate={apath}{0pt}{1pt}, + restore=apath, +]; +\draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt]; +\end{tikzpicture} +\end{example} + +\begin{example} +\begin{tikzpicture} +\draw[spath/save=npath] (0,0) foreach \k in {1,...,4} { -- ++(1,0) +(0,0)}; +\draw[green] (0,0) -- +(0,-3pt) foreach \k in {1,...,4} { -- +(0,-3pt) ++(1,0)} -- +(0,-3pt); + +\tikzset{ + spath/.cd, + insert gaps after components={npath}{10pt}{1,3}, + get components of={npath}\components, +} + +\tikzset{ + path 1/.style={ + red, + }, +} + +\foreach[count=\k] \cpt in \components { + \path[ + draw, + path \k/.try, + spath/.cd, + translate=\cpt{0pt}{\k pt}, + restore=\cpt, + ] +(0,3pt) -- +(0,-3pt); + \node[text=red] at (spath cs:{\cpt} .5) {\(\k\)}; +} +\end{tikzpicture} +\end{example} + +\item Intersections. + +One of the main motivations for implementing the intersection routines was to provide a different way of drawing knots and links and similar diagrams. + +\begin{enumerate} + +\item Define the two paths for the braid (usually these will be defined with |\path|). +\begin{example} +\begin{tikzpicture}[ + use Hobby shortcut, +] +\draw[spath/save global=pathA] (0,0) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1); +\draw[spath/save global=pathB] (0,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1) to[out=0,in=180] ++(2,-1) to[out=0,in=180] ++(2,1); +\end{tikzpicture} +\end{example} + +\item Split the paths at their mutual intersections and render them with a count of the components. + +\begin{example} +\begin{tikzpicture} +\tikzset{ + spath/.cd, + split at intersections={pathA}{pathB}, + get components of={pathA}\pathAcomponents, + get components of={pathB}\pathBcomponents, +} + +\foreach[count=\k] \cpt in \pathAcomponents { + \draw[spath/restore=\cpt,-Circle]; + \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; +} + +\foreach[count=\k] \cpt in \pathBcomponents { + \draw[spath/restore=\cpt,-Circle]; + \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; +} +\end{tikzpicture} +\end{example} + +\item Now we insert gaps after certain components in each path and then render the components. +To show that the gaps are genuine, we use a patterned background. +Although the paths were defined globally, the splitting in the previous example was local so we need to repeat it in this one. + +\begin{example} +\begin{tikzpicture} +\tikzset{ + spath/.cd, + split at intersections={pathA}{pathB}, + insert gaps after components={pathA}{5pt}{1,3}, + join components={pathA}{3,5}, + get components of={pathA}\pathAcomponents, + insert gaps after components={pathB}{5pt}{2,4}, + join components={pathB}{2,4}, + get components of={pathB}\pathBcomponents, +} + +\fill[red!50!white] (-.5,-.5) rectangle (8.5,1.5); +\fill[pattern=bricks, pattern color=white] (-.5,-.5) rectangle (8.5,1.5); + +\foreach[count=\k] \cpt in \pathAcomponents { + \draw[blue, line width=2pt,spath/restore=\cpt]; + \node[fill=cyan, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .3) {\(\k\)}; +} + +\foreach[count=\k] \cpt in \pathBcomponents { + \draw[green, line width=2pt,spath/restore=\cpt]; + \node[fill=green!50, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .3) {\(\k\)}; +} +\end{tikzpicture} +\end{example} +\end{enumerate} + +\item This example is notable because many of the intersection points are where segments of the path end, showing that the algorithm works well even in this circumstance. + +\begin{enumerate} +\item Here's the original path. +\begin{example} +\begin{tikzpicture} +\draw[spath/save global=spiral] (5,0) -- (2.5,0) -- ++(0,-.25) -- ++(-2.5,0) +arc[radius=2.25cm,start angle=180,end angle=90] +arc[radius=2cm,start angle=90, delta angle=-180] +arc[radius=1.75cm,start angle=-90, delta angle=-180] +arc[radius=1.5cm,start angle=90, delta angle=-180] +arc[radius=1.25cm,start angle=-90, delta angle=-180] +arc[radius=1cm,start angle=90, delta angle=-180] +arc[radius=.75cm,start angle=-90, delta angle=-180] +arc[radius=.5cm,start angle=90, delta angle=-180] +; +\end{tikzpicture} +\end{example} + +\item This renders labels on each component after splitting. +\begin{example} +\begin{tikzpicture} +\tikzset{ + spath/.cd, + split at self intersections=spiral, + get components of={spiral}\pathcomponents, +} + +\foreach[count=\k] \cpt in \pathcomponents { + \draw[spath/restore=\cpt,-|]; + \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)}; +} +\end{tikzpicture} +\end{example} + +\item Finally, we put the gaps in where we want them. + +\begin{example} +\begin{tikzpicture} +\tikzset{ + spath/.cd, + split at self intersections=spiral, + insert gaps after components={spiral}{10pt}{1,3,5,7,10,11,14}, + spot weld=spiral, + get components of={spiral}\pathcomponents, +} + +\foreach[count=\k] \cpt in \pathcomponents { + \draw[blue, line width=2pt,spath/restore=\cpt]; +} +\end{tikzpicture} +\end{example} +\end{enumerate} + +\item Here's a trefoil knot, demonstrating the \texttt{knot} style that simplifies creating knots. +\begin{example} +\begin{tikzpicture}[ + use Hobby shortcut, + every trefoil component/.style={ultra thick, draw, red}, + trefoil component 1/.style={blue}, +] +\path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2); +\tikzset{spath/knot={trefoil}{8pt}{1,3,5}} +\end{tikzpicture} +\end{example} +\end{enumerate} + \end{document} diff --git a/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf b/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf Binary files differindex be1f2941bd8..77d3e3b723c 100644 --- a/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf +++ b/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf diff --git a/Master/texmf-dist/source/latex/spath3/spath3.dtx b/Master/texmf-dist/source/latex/spath3/spath3.dtx deleted file mode 100644 index 9d6ae2825df..00000000000 --- a/Master/texmf-dist/source/latex/spath3/spath3.dtx +++ /dev/null @@ -1,4228 +0,0 @@ -% \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-2019 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 - knots_doc.tex -and the derived files spath3.ins, - spath3_code.pdf, - spath3.sty, - tikzlibrarycalligraphy.code.tex - tikzlibraryknots.code.tex - calligraphy.pdf - knots.pdf - README - -\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{4488} -% -% \CharacterTable -% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z -% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z -% Digits \0\1\2\3\4\5\6\7\8\9 -% Exclamation \! Double quote \" Hash (number) \# -% Dollar \$ Percent \% Ampersand \& -% Acute accent \' Left paren \( Right paren \) -% Asterisk \* Plus \+ Comma \, -% Minus \- Point \. Solidus \/ -% Colon \: Semicolon \; Less than \< -% Equals \= Greater than \> Question mark \? -% Commercial at \@ Left bracket \[ Backslash \\ -% Right bracket \] Circumflex \^ Underscore \_ -% Grave accent \` Left brace \{ Vertical bar \| -% Right brace \} Tilde \~} -% -% -% \changes{1.0}{2011/05/03}{Converted to DTX file} -% \changes{1.1}{2016/02/19}{Fixes due to changes in LaTeX3} -% \changes{1.2}{2019/02/12}{More fixes due to changes in LaTeX3} -% -% \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} where 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} {2019/02/12} {1.2} {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 -\fp_new:N \l__spath_tmpa_fp -\fp_new:N \l__spath_tmpb_fp -\int_new:N \l__spath_tmpa_int -\int_new:N \g__spath_map_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_new:N \g__spath_closepath_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} -\tl_set:Nn \g__spath_closepath_tl {\pgfsyssoftpath@closepathtoken} -% \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_item: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} - { - \tl_set:Nn #3 {##2} - \prg_return_true: - } - { \prg_return_false: } -} -\cs_generate_variant:Nn \spath_put:nnn {nnV, nnx, nno} -\cs_generate_variant:Nn \__spath_get:nn {Vn} -\cs_generate_variant:Nn \__spath_get:nnN {VnN} -% \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__spath_tmpa_tl - \spath_clear_new:n {#1} - \spath_put:nnV {#1} {path} \l__spath_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 {VnN} -% \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 -} -\cs_generate_variant:Nn \spath_generate_finalpoint:n {V} -% \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:NnF \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:NnF \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 - - \fp_set:Nn \l__spath_tmpa_fp {\tl_head:N \l__spath_tmpa_tl * #2} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - \fp_set:Nn \l__spath_tmpb_fp {\tl_head:N \l__spath_tmpa_tl * #3} - \tl_clear:N \l__spath_tmpb_tl - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - \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} - - \fp_set:Nn \l__spath_tmpa_fp {\tl_head:N \l__spath_tmpa_tl * #2} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - - \fp_set:Nn \l__spath_tmpb_fp {\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 - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl - } - } -} -\cs_generate_variant:Nn \spath_scale: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_scale:nn #1#2 -{ - \spath_scale:nnn {#1} #2 -} - -\cs_generate_variant:Nn \spath_scale:nn {nV} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\spath_transform:nnnnnnn} -% Applies an affine (matrix and vector) transformation to path. -% The matrix is specified in rows first. -% \begin{macrocode} -\cs_new_nopar:Npn \spath_transform:nnnnnnn #1#2#3#4#5#6#7 -{ - \tl_map_inline:Nn \g__spath_moveable_attributes - { - \spath_if_in:nnT {#1} {##1} - { - \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl - \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpb_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_head:N \l__spath_tmpa_tl} - \fp_set:Nn \l__spath_tmpa_fp {\l__spath_tmpa_tl * #2 + \l__spath_tmpb_tl * #3 + #6} - \fp_set:Nn \l__spath_tmpb_fp {\l__spath_tmpa_tl * #4 + \l__spath_tmpb_tl * #5 + #7} - \tl_clear:N \l__spath_tmpb_tl - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - \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} - \tl_set:Nx \l_tmpa_tl {\tl_head:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - \tl_set:Nx \l_tmpb_tl {\tl_head:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - - \fp_set:Nn \l__spath_tmpa_fp {\l_tmpa_tl * #2 + \l_tmpb_tl * #3 + #6} - \fp_set:Nn \l__spath_tmpb_fp {\l_tmpa_tl * #4 + \l_tmpb_tl * #5 + #7} - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl - } - } -} - -\cs_generate_variant:Nn \spath_transform:nnnnnnn {nxxxxxx} -% \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_transform:nn #1#2 -{ - \spath_transform:nnnnnnn {#1} #2 -} - -\cs_generate_variant:Nn \spath_transform:nn {nV} -% \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} { - \use:c {spath_generate_reverse path:n} {#1} - } - \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:nn {#1} {#2}} - {\spath_put:nnV {#1} {#2} \l__spath_tmpb_tl} - \tl_if_empty:NTF \l__spath_tmpa_tl - {\spath_remove:nn {#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} -% -% \begin{macro}{\spath_bake_round:n} -% Ought to clear the reverse path, if set. -% \begin{macrocode} -\cs_new_nopar:Npn \spath_bake_round:n #1 -{ - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl - \pgf@@processround\l__spath_tmpa_tl\l__spath_tmpb_tl - \spath_put:nnV {#1} {path} \l__spath_tmpb_tl -} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\spath_close_path:n} -% Appends a close path to the end of the path, and to the end of the reverse path. -% For now, the point is the initial or final point (respectively). -% To be future proof, it ought to be the point of the adjacent move to. -% \begin{macrocode} -\cs_new_nopar:Npn \spath_close_path:n #1 -{ - \spath_get:nnN {#1} {initial point} \l__spath_tmpb_tl - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_closepath_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:nnT {#1} {reverse path} - { - \spath_get:nnN {#1} {final point} \l__spath_tmpb_tl - \__spath_get:nnN {#1} {reverse path} \l__spath_tmpa_tl - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_closepath_tl - \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl - \spath_put:nnV {#1} {reverse path} \l__spath_tmpa_tl - } -} -% \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__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_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 { __spath_map_ \int_use:N \g__spath_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__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_map_int :w } ##1 ##2 {#2} - \spath_map_segment_function:Nc #1 { __spath_map_ \int_use:N \g__spath_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__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_map_int :w } ##1 ##2 {#2} - \spath_get:nnN {#1} {path} \l__spath_tmpd_tl - \spath_map_segment_function:Nc \l__spath_tmpd_tl { __spath_map_ \int_use:N \g__spath_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:NnF \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} - - } - - \g__spath_closepath_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} - - } - - } - { - - \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_clear_new:N #3 - \spath_get:nnN {#1} {#2} #3 -} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\SPathShow} -% \begin{macrocode} -\NewDocumentCommand \SPathShow { 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_scale: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_scale: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} {2}} - {\tl_item:nn {#2} {3}} - } - \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 -\int_new:N \l__cal_label_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_annotate_bool -\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 - -\cs_generate_variant:Nn \tl_put_right:Nn {Nv} -% \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} - }, - annotate/.style={ - annotate~if, - annotate~reset, - annotation~style/.update~value={#1}, - }, - annotate~if/.default={true}, - annotate~if/.code={ - \tl_if_eq:nnTF {#1} {true} - { - \bool_set_true:N \l__cal_annotate_bool - } - { - \bool_set_false:N \l__cal_annotate_bool - } - }, - annotate~reset/.code={ - \int_gzero:N \l__cal_label_int - }, - annotation~style/.initial={draw,->}, - annotation~shift/.initial={(0,1ex)}, - every~annotation~node/.initial={anchor=south~west}, - annotation~node~style/.code~2~args={ - \tl_set:cn {l__cal_annotation_style_ #1 _tl}{#2} - }, - tl~use:N/.code={ - \exp_args:NV \pgfkeysalso #1 - }, - tl~use:c/.code={ - \tl_if_exist:cT {#1} - { - \exp_args:Nv \pgfkeysalso {#1} - } - }, - /handlers/.update~style/.code={ - \tl_if_eq:nnF {#1} {\pgfkeysnovalue} - { - \pgfkeys{\pgfkeyscurrentpath/.code=\pgfkeysalso{#1}} - } - }, - /handlers/.update~value/.code={ - \tl_if_eq:nnF {#1} {\pgfkeysnovalue} - { - \pgfkeyssetvalue{\pgfkeyscurrentpath}{#1} - } - } -} -% \end{macrocode} -% -% Some wrappers around the TikZ keys. -% \begin{macrocode} -\NewDocumentCommand \pen { O{} } -{ - \path[define~ pen,every~ calligraphy~ pen/.try,#1] -} - -\NewDocumentCommand \definepen { O{} } -{ - \tikz \path[define~ pen,every~ calligraphy~ pen/.try,#1] -} - -\NewDocumentCommand \calligraphy { O{} } -{ - \path[use~ pen,every~ calligraphy/.try,#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: - \pgfsys@beginscope - - \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__cal_tmpa_tl - \spath_translate:nV {calligraphy temp path} \l__cal_tmpa_tl - - \__spath_get:nnN {####1} {length} \l__cal_tmpa_tl - - \int_compare:nTF {\l__cal_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__cal_tmpa_tl - - \tikz@options - \dim_set:Nn \l__cal_line_width_dim {\pgflinewidth} - \cal_maybe_taper:N \l__cal_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} - - \tl_clear:N \l__cal_tmpa_tl - \tl_set:Nn \l__cal_tmpa_tl {fill=\pgfkeysvalueof{/tikz/pen~colour},draw=none} - \tl_if_exist:cT {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} - { - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} - } - \tl_if_exist:cT {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} - { - \tl_put_right:Nn \l__cal_tmpa_tl {,} - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} - } - \tl_if_exist:cT {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} - { - \tl_put_right:Nn \l__cal_tmpa_tl {,} - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} - } - \spath_tikz_path:Vn \l__cal_tmpa_tl {calligraphy temp path} - - } - \pgfsys@endscope - \group_end: - } - \bool_if:NT \l__cal_annotate_bool - { - \spath_clone:nn {##1} {calligraphy temp path} - \tl_set_eq:Nc \l_tmpa_tl {l__spath_list_calligraphy pen #2} - \tl_reverse:N \l_tmpa_tl - \tl_set:Nx \l_tmpa_tl {\tl_head:N \l_tmpa_tl} - \spath_generate_finalpoint:V \l_tmpa_tl - \spath_get:VnN \l_tmpa_tl {final point} \l_tmpa_tl - \spath_translate:nV {calligraphy temp path} \l_tmpa_tl - \tikz@scan@one@point\pgfutil@firstofone\pgfkeysvalueof{/tikz/annotation~shift} - \spath_translate:nnn {calligraphy temp path} {\pgf@x} {\pgf@y} - - \pgfkeysgetvalue{/tikz/annotation~style}{\l_tmpa_tl} - \spath_tikz_path:Vn \l_tmpa_tl {calligraphy temp path} - \spath_get:nnN {calligraphy temp path} {final point} \l_tmpa_tl - \exp_last_unbraced:NV \pgfqpoint \l_tmpa_tl - \begin{scope}[reset~ cm] - \node[every~annotation~node/.try,tl~use:c = {l__cal_annotation_style_ \int_use:N \l__cal_tmpa_int _tl}] at (\pgf@x,\pgf@y) {\int_use:N \l__cal_tmpa_int}; - \end{scope} - } - } -} -% \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:NnF ##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:NnF ##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:NnF \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:NnF \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 -\tl_new:N \l__knot_aux_tl -\tl_new:N \l__knot_auxa_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_bg_radius_dim -\dim_new:N \l__knot_clip_draw_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_new:N \l__knot_save_bool - -\seq_new:N \l__knot_nodes_seq - -\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_eq:nnTF {\pgfkeysnovalue} {#1} - { - \tikz@addoption{\pgfsetinnerstrokecolor{.}} - } - { - \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}, - save~ intersections/.is~ choice, - save~ intersections/.default=true, - save~ intersections/true/.code={ - \bool_set_true:N \l__knot_save_bool - }, - save~ intersections/false/.code={ - \bool_set_false:N \l__knot_save_bool - }, - 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_bg_radius_dim {#1} - \dim_set:Nn \l__knot_clip_draw_radius_dim {#1+2pt} - }, - clip~ draw~ radius/.code={ - \dim_set:Nn \l__knot_clip_draw_radius_dim {#1} - }, - clip~ background~ radius/.code={ - \dim_set:Nn \l__knot_clip_bg_radius_dim {#1} - }, - clip~ radius=10pt, - end~ tolerance/.code={ - \dim_set:Nn \l__knot_tolerance_dim {#1} - }, - end~ tolerance=14pt, - clip/.style={ - clip - }, - background~ clip/.style={ - clip - }, - 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} - }, - ignore~ crossing/.code={% - \tl_clear_new:c {l__knot_ignore_crossing_#1} - \tl_set:cn {l__knot_ignore_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 - \seq_gclear:N \l__knot_nodes_seq -} -% \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 { - \exp_not:N \node[coordinate, - pin={[node~ contents={\int_use:N \l__knot_intersections_int},knot~ diagram/draft/crossing~ label, knot~ diagram/draft/crossing~ \int_use:N \l__knot_intersections_int \c_space_tl label/.try] - }] - } - } - { - \tl_set:Nn \l__knot_node_tl {\exp_not:N \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} -% Draw the crossing nodes -% \begin{macrocode} - \seq_use:Nn \l__knot_nodes_seq {} - } -% \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_bake_round:n {knot strand #1} - \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:NnF #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 - - \bool_if:nTF { - \l__knot_save_bool - && - \tl_if_exist_p:c {knot~ intersections~ \tl_use:N \l__knot_name_tl - \tl_use:N \l__knot_tmpa_tl - \tl_use:N \l__knot_tmpb_tl} - } - { - \tl_use:c {knot~ intersections~ \tl_use:N \l__knot_name_tl - \tl_use:N \l__knot_tmpa_tl - \tl_use:N \l__knot_tmpb_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 - } - \knot_save_intersections:VV \l__knot_tmpa_tl \l__knot_tmpb_tl - \group_end: -} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\knot_save_intersections:nn} -% \begin{macrocode} -\cs_new_protected_nopar:Npn \knot_save_intersections:nn #1#2 -{ - \bool_if:NT \l__knot_save_bool - { - \tl_clear:N \l__knot_aux_tl - \tl_put_right:Nn \l__knot_aux_tl - { - \def\pgfintersectionsolutions - } - \tl_put_right:Nx \l__knot_aux_tl - { - {\int_eval:n {\pgfintersectionsolutions}} - } - \int_compare:nT {\pgfintersectionsolutions > 0} - { - \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} - { - \pgfpointintersectionsolution{##1} - \dim_set:Nn \l__knot_tmpa_dim {\pgf@x} - \dim_set:Nn \l__knot_tmpb_dim {\pgf@y} - \tl_put_right:Nn \l__knot_aux_tl - { - \expandafter\def\csname pgfpoint@intersect@solution@##1\endcsname - } - \tl_put_right:Nx \l__knot_aux_tl - { - {\exp_not:N \pgf@x=\dim_use:N \l__knot_tmpa_dim\exp_not:N\relax\exp_not:N \pgf@y =\dim_use:N \l__knot_tmpb_dim\relax} - } - } - \tl_set:Nn \l__knot_auxa_tl {\expandafter \gdef \csname knot~ intersections~} - \tl_put_right:Nx \l__knot_auxa_tl {\tl_use:N \l__knot_name_tl - #1 - #2} - \tl_put_right:Nn \l__knot_auxa_tl {\endcsname} - \tl_put_right:Nx \l__knot_auxa_tl {{\tl_to_str:N \l__knot_aux_tl}} - \protected@write\@auxout{}{\tl_to_str:N \l__knot_auxa_tl} - } - } -} -\cs_generate_variant:Nn \knot_save_intersections:nn {VV} -% \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 user 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 intersection test. -% If the intersection finder finds too many, it might be useful to ignore some. -% \begin{macrocode} - \bool_if:nF - { - \tl_if_exist_p:c {l__knot_ignore_crossing_ \int_use:N - \l__knot_intersections_int} - && - ! \tl_if_empty_p:c {l__knot_ignore_crossing_ \int_use: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 - && - \tl_if_exist_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - && - !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - } - { - \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 - && - \tl_if_exist_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - && - !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - } - { - \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 - && - \tl_if_exist_p:c {knot next \tl_use:N \l__knot_tmpg_tl} - && - !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - } - { - \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 - && - \tl_if_exist_p:c {knot previous \tl_use:N - \l__knot_tmpg_tl} - && - !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} - } - { - \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} - \pgfscope - \group_begin: - \tikzset{knot~ diagram/every~ intersection/.try, every~ intersection/.try, 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: - \endpgfscope -% \end{macrocode} -% This ends the boolean as to whether to consider the intersection at all -% \begin{macrocode} - } -% \end{macrocode} -% And stick a coordinate possibly with a label at the crossing. -% \begin{macrocode} - \seq_gpush:Nx \l__knot_nodes_seq { \l__knot_node_tl (\l__knot_name_tl \c_space_tl \int_use:N \l__knot_intersections_int) at (\dim_use:N \l__knot_tmpa_dim, \dim_use:N \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 { \l__knot_tmpa_dim - \tl_item:Nn #1 {1}} - + - \dim_abs:n { \l__knot_tmpb_dim - \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 - \path[knot~ diagram/background~ clip] (#2, #3) circle[radius=\l__knot_clip_bg_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 - \path[knot~ diagram/clip] (#2, #3) circle[radius=\l__knot_clip_draw_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} - -\cs_new_nopar:Npn \knot_draw_crossing:nn #1#2 -{ - \tikz@scan@one@point\pgfutil@firstofone #2 \relax - \knot_draw_crossing:nVV {#1} \pgf@x \pgf@y -} -% \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 - \tl_set_eq:Nc \l__knot_tmpa_tl {l__knot_options_strand #1} - \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:NnF #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_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_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}} - } - } - \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_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_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}} - } - } - \g__spath_closepath_tl - { - \tl_show:N #2 - \int_gincr:N \l__knot_filaments_int - \spath_clear_new:n {knot filament \int_use:N \l__knot_filaments_int} - \tl_clear:N \l_tmpa_tl - \tl_put_right:Nx {\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_put_right:Nx {\tl_item:Nn #2 {5}\tl_item:Nn #2 {6}} - \tl_show:N \l_tmpa_tl - \spath_put:nnV {knot filament \int_use:N \l__knot_filaments_int} {path} \l_tmpa_tl - \tl_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_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:nn} - \tl_put_right:Nx \l__knot_redraws_tl { - {strand #1} {#2}% {\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_code.dtx b/Master/texmf-dist/source/latex/spath3/spath3_code.dtx new file mode 100644 index 00000000000..c5c584c4f81 --- /dev/null +++ b/Master/texmf-dist/source/latex/spath3/spath3_code.dtx @@ -0,0 +1,6719 @@ +% \iffalse meta-comment +%<*internal> +\iffalse +%</internal> +%<*readme> +---------------------------------------------------------------- +spath3 --- LaTeX3 functions for manipulating PGF soft paths +E-mail: loopspace@mathforge.org +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +---------------------------------------------------------------- + +This package defines some 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 l3docstrip.tex +\keepsilent +\askforoverwritefalse +\preamble +---------------------------------------------------------------- +spath3 --- Functions for manipulating PGF soft paths +E-mail: loopspace@mathforge.org +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +---------------------------------------------------------------- + +\endpreamble +\postamble + +Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> + +This work may be distributed and/or modified under the +conditions of the LaTeX Project Public License (LPPL), either +version 1.3c of this license or (at your option) any later +version. The latest version of this license is in the file: + +http://www.latex-project.org/lppl.txt + +This work is "maintained" (as per LPPL maintenance status) by +Andrew Stacey. + +This work consists of the files spath3.dtx + calligraphy_doc.tex + knots_doc.tex + spath3.tex +and the derived files spath3.ins, + spath3_code.pdf, + spath3.sty, + tikzlibrarycalligraphy.code.tex + tikzlibraryknots.code.tex + tikzlibraryspath3.code.tex + calligraphy.pdf + knots.pdf + spath3.pdf + README + +\endpostamble +\usedir{tex/latex/spath3} +\generate{ + \file{spath3.sty}{\from{\jobname.dtx}{spath3}} +} +\generate{ + \file{tikzlibrarycalligraphy.code.tex}{\from{\jobname.dtx}{calligraphy}} +} +\generate{ + \file{tikzlibraryknots.code.tex}{\from{\jobname.dtx}{knots}} +} +\generate{ + \file{tikzlibraryspath3.code.tex}{\from{\jobname.dtx}{tikzspath3}} +} +%</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=[LaTeX]TeX, + basicstyle=\small\ttfamily, + keepspaces=true, + columns=fullflexible +} + +\usepackage{fancyvrb} + +\newenvironment{example} + {\VerbatimEnvironment + \begin{VerbatimOut}[gobble=2]{example.out}} + {\end{VerbatimOut} + \begin{center} +% \setlength{\parindent}{0pt} + \fbox{\begin{minipage}{.9\linewidth} + \lstinputlisting[]{example.out} + \end{minipage}} + \fbox{\begin{minipage}{.9\linewidth} + \centering + \input{example.out} + \end{minipage}} +\end{center} +} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \CheckSum{6848} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \changes{1.0}{2011/05/03}{Converted to DTX file} +% \changes{1.1}{2016/02/19}{Fixes due to changes in LaTeX3} +% \changes{1.2}{2019/02/12}{More fixes due to changes in LaTeX3} +% \changes{1.4}{2020/12/18}{A fair amount of code reimplementation and reorganisation, together with defining TikZ keys to make functions available for use.} +% \changes{2.0}{2021/01/19}{Refactored the code to remove the OO approach and make it functional, introduced the spath3 TikZ library to provide a user interface.} +% +% \DoNotIndex{\newcommand,\newenvironment} +% +% \providecommand*{\url}{\texttt} +% \GetFileInfo{spath3.sty} +% \title{The \textsf{spath3} package: code} +% \author{Andrew Stacey \\ \url{loopspace@mathforge.org}} +% \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} where 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 was originally not really intended for use by end users but as a foundation on which other packages can be built. +% However, over the years I've found myself using it at ever higher levels and so a set of interfaces has been designed using TikZ keys. +% +% It also provides the engine that drives a few other packages, such as the \Verb+calligraphy+, \Verb+knot+, and \Verb+penrose+ packages. +% The first two of these are subpackages of this one. +% The \Verb+calligraphy+ package simulates a calligraphic pen stroking a path. +% The \Verb+knots+ package can be used to draw knot (and similar) diagrams. +% +% For usage, see the documentation of the following packages (\Verb+texdoc <package>+): +% +% \begin{itemize} +% \item \Verb+calligraphy+ +% \item \Verb+knots+ +% \item \Verb+penrose+ +% \item \Verb+spath3+ (\emph{this} document is the code, there's another which focusses on usage) +% \end{itemize} +% +% \section{Technical Details} +% +% 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. +% +% In the original implementation, I wrapped this token list in a \Verb+prop+ to store useful information along with the path. +% Over time, this additional structure has proved a little unwieldy and I've pared it back to working primarily with the original soft path as a token list. +% +% A frequent use of this package is to break a path into pieces and do something with each of those pieces. +% To that end, there are various words that I use to describe the levels of the structure of a path. +% +% At the top level is the path itself. +% At the bottom level are the triples of the form \Verb+\macro{dim}{dim}+, as described above. +% In between these are the \emph{segments} and \emph{components}. +% +% A \emph{segment} is a minimal drawing piece. +% Thus it might be a straight line or a B\'ezier curve. +% When a path is broken into segments then each segment is a complete path so it isn't simply a selection of triples from the original path. +% +% A \emph{component} is a minimal connected section of the path. +% So every component starts with a move command and continues until the next move command. +% For ease of implementation (and to enable a copperplate pen in the calligraphy package!), an isolated move is considered as a component. +% Thus the following path consists of three components: +% +% \begin{Verbatim} +% \path (0,0) -- (1,0) (2,0) (3,0) to[out=0,in=90] (4,0); +% \end{Verbatim} +% +% \StopEventually{} +% +% \section{Implementation} +% +% \iffalse +%<*spath3> +% \fi +% \subsection{Initialisation} +% +% \begin{macrocode} +%<@@=spath> +% \end{macrocode} +% +% Load the \LaTeX3 foundation and register us as a \LaTeX3\ package. +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\RequirePackage{expl3} +\RequirePackage{pgf} +\ProvidesExplPackage {spath3} {2021/01/19} {2.0} {Functions for +manipulating PGF soft paths} +\RequirePackage{xparse} +% \end{macrocode} +% +% Utilities copied from \url{https://github.com/loopspace/LaTeX3-Utilities} for adding something in braces to a token list. +% \begin{macrocode} +\cs_new_protected:Nn \@@_tl_put_right_braced:Nn +{ + \tl_put_right:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \@@_tl_put_right_braced:Nn { NV, cV, cv, Nx, cx } + +\cs_new_protected:Nn \@@_tl_gput_right_braced:Nn +{ + \tl_gput_right:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \@@_tl_gput_right_braced:Nn { NV, cV, cv, Nx, cx } +\cs_new_protected:Nn \@@_tl_put_left_braced:Nn +{ + \tl_put_left:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \@@_tl_put_left_braced:Nn { NV, cV, cv, Nx, cx } + +\cs_new_protected:Nn \@@_tl_gput_left_braced:Nn +{ + \tl_gput_left:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \@@_tl_gput_left_braced:Nn { NV, cV, cv, Nx, cx } +% \end{macrocode} +% +% We need a slew of temporary variables. +% \begin{macrocode} +\tl_new:N \l_@@_tmpa_tl +\tl_new:N \l_@@_tmpb_tl +\tl_new:N \l_@@_tmpc_tl +\tl_new:N \l_@@_tmpd_tl +\tl_new:N \l_@@_tmpe_tl + +\seq_new:N \l_@@_tmpa_seq +\seq_new:N \l_@@_tmpb_seq + +\tl_new:N \g_@@_output_tl +\int_new:N \g_@@_output_int +\seq_new:N \g_@@_output_seq + +\dim_new:N \l_@@_tmpa_dim +\dim_new:N \l_@@_tmpb_dim +\dim_new:N \l_@@_move_x_dim +\dim_new:N \l_@@_move_y_dim +\fp_new:N \l_@@_tmpa_fp +\fp_new:N \l_@@_tmpb_fp +\int_new:N \l_@@_tmpa_int + +\bool_new:N \g_@@_output_bool +\bool_new:N \l_@@_closed_bool +% \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. +% These are global constants so that they can be used in other packages. +% \begin{macrocode} +\tl_const:Nn \c_spath_moveto_tl {\pgfsyssoftpath@movetotoken} +\tl_const:Nn \c_spath_lineto_tl {\pgfsyssoftpath@linetotoken} +\tl_const:Nn \c_spath_curveto_tl {\pgfsyssoftpath@curvetotoken} +\tl_const:Nn \c_spath_curvetoa_tl {\pgfsyssoftpath@curvetosupportatoken} +\tl_const:Nn \c_spath_curvetob_tl {\pgfsyssoftpath@curvetosupportbtoken} +\tl_const:Nn \c_spath_closepath_tl {\pgfsyssoftpath@closepathtoken} +% \end{macrocode} +% +% +% We will want to be able to use anonymous spaths internally, so we create a global counter that we can use to refer to them. +% \begin{macrocode} +\int_new:N \g_@@_anon_int +\int_gzero:N \g_@@_anon_int +% \end{macrocode} +% +% Groups and iterations don't mix well and I haven't got a good scheme for protecting local calculations when iterating, so we do our best with iteration-specific variables. +% \begin{macrocode} +\tl_new:N \l_@@_itera_tl +\tl_new:N \l_@@_iterb_tl +\tl_new:N \l_@@_iterc_tl +\tl_new:N \l_@@_iterd_tl +\tl_new:N \l_@@_iterp_tl +\dim_new:N \l_@@_itera_dim +\dim_new:N \l_@@_iterb_dim +\seq_new:N \l_@@_iter_seq +% \end{macrocode} +% +% And some error messages +% \begin{macrocode} +\msg_new:nnn { spath3 } { unknown path construction } { The~ path~ construction~ element~ #1~ is~ not~ currently~ supported.} +% \end{macrocode} +% +% +% \subsection{Functional Implementation} +% +% In the functional approach, we start with a token list containing a soft path and do something to it (either calculate some information or manipulate it in some fashion). +% We then store that information, or the manipulated path, in an appropriate macro. +% The macro to store it in is the first argument. +% These functions occur in two versions, the one with the \texttt{g} makes the assignment global. +% +% \begin{macro}{ +% \spath_segments_to_seq:Nn, +% \spath_segments_gto_seq:Nn +%} +% Splits a soft path into \emph{segments}, storing the result in a sequence. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_segments_to_seq:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_itera_tl {#1} + \tl_clear:N \l_@@_iterb_tl + \seq_clear:N \l_@@_iter_seq + \dim_zero:N \l_@@_itera_dim + \dim_zero:N \l_@@_iterb_dim + + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_itera_tl + } + { + \tl_set:Nx \l_@@_iterc_tl {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + \tl_case:NnF \l_@@_iterc_tl + { + \c_spath_moveto_tl + { + \tl_set_eq:NN \l_@@_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_itera_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_iterb_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_set:Nx \l_@@_iterd_tl {\tl_head:N \l_@@_itera_tl} + \tl_if_eq:NNF \l_@@_iterd_tl \c_spath_moveto_tl + { + \tl_clear:N \l_@@_iterb_tl + } + + } + + \c_spath_lineto_tl + { + \tl_set_eq:NN \l_@@_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_iterb_tl + { + {\dim_use:N \l_@@_itera_dim} + {\dim_use:N \l_@@_iterb_dim} + } + \tl_put_right:NV \l_@@_iterb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_itera_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_iterb_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + } + + \c_spath_curvetoa_tl + { + \tl_set_eq:NN \l_@@_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_iterb_tl + { + {\dim_use:N \l_@@_itera_dim} + {\dim_use:N \l_@@_iterb_dim} + } + \tl_put_right:NV \l_@@_iterb_tl \c_spath_curvetoa_tl + + \prg_replicate:nn {2} { + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + \tl_put_right:Nx \l_@@_iterb_tl {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + } + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_itera_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_iterb_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + } + + \c_spath_closepath_tl + { + \tl_set_eq:NN \l_@@_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_iterb_tl + { + {\dim_use:N \l_@@_itera_dim} + {\dim_use:N \l_@@_iterb_dim} + } + \tl_put_right:NV \l_@@_iterb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_itera_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_iterb_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + } + + } + { + + \tl_set_eq:NN \l_@@_iterb_tl \l_@@_iterc_tl + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_itera_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + \tl_put_right:Nx \l_@@_iterb_tl {{\tl_head:N \l_@@_itera_tl}} + \dim_set:Nn \l_@@_iterb_dim {\tl_head:N \l_@@_itera_tl} + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + + } + + \tl_if_empty:NF \l_@@_iterb_tl + { + \seq_put_right:NV \l_@@_iter_seq \l_@@_iterb_tl + } + \tl_clear:N \l_@@_iterb_tl + } + + \seq_gclear:N \g_@@_output_seq + \seq_gset_eq:NN \g_@@_output_seq \l_@@_iter_seq + \group_end: +} +\cs_new_protected_nopar:Npn \spath_segments_to_seq:Nn #1#2 +{ + \@@_segments_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_set_eq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_segments_to_seq:Nn {NV, cn, cV, Nv, cv} +\cs_new_protected_nopar:Npn \spath_segments_gto_seq:Nn #1#2 +{ + \@@_segments_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_gset_eq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_segments_gto_seq:Nn {NV, cn, cV, Nv, cv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_components_to_seq:Nn, +% \spath_components_gto_seq:Nn, +% \spath_components_to_clist:Nn, +% \spath_components_gto_clist:Nn, +% } +% Splits a soft path into \emph{components}, storing the result in a sequence or a clist. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_components_to_seq:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_itera_tl {#1} + \seq_clear:N \l_@@_iter_seq + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + \tl_put_right:NV \l_@@_itera_tl \c_spath_moveto_tl + \tl_set_eq:NN \l_@@_iterb_tl \c_spath_moveto_tl + \bool_do_until:nn { + \tl_if_empty_p:N \l_@@_itera_tl + } + { + \tl_set:Nx \l_@@_iterc_tl {\tl_head:N \l_@@_itera_tl} + \tl_if_eq:NNT \l_@@_iterc_tl \c_spath_moveto_tl + { + \seq_put_right:NV \l_@@_iter_seq \l_@@_iterb_tl + \tl_clear:N \l_@@_iterb_tl + } + \tl_if_single:NTF \l_@@_iterc_tl + { + \tl_put_right:NV \l_@@_iterb_tl \l_@@_iterc_tl + } + { + \tl_put_right:Nx \l_@@_iterb_tl {{\l_@@_iterc_tl}} + } + \tl_set:Nx \l_@@_itera_tl {\tl_tail:N \l_@@_itera_tl} + } + + \seq_gclear:N \g_@@_output_seq + \seq_gset_eq:NN \g_@@_output_seq \l_@@_iter_seq + \group_end: +} +\cs_new_protected_nopar:Npn \spath_components_to_seq:Nn #1#2 +{ + \@@_components_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_set_eq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_components_to_seq:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_gto_seq:Nn #1#2 +{ + \@@_components_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_gset_eq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_components_gto_seq:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_to_clist:Nn #1#2 +{ + \@@_components_to_seq:n {#2} + \clist_clear_new:N #1 + \clist_set_from_seq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_components_to_clist:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_gto_clist:Nn #1#2 +{ + \@@_components_to_seq:n {#2} + \clist_clear_new:N #1 + \clist_gset_from_seq:NN #1 \g_@@_output_seq + \seq_gclear:N \g_@@_output_seq +} +\cs_generate_variant:Nn \spath_components_gto_clist:Nn {NV, cn, cV, cv, Nv} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\spath_length:n} +% Counts the number of triples in the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_length:n #1 +{ + \int_eval:n {\tl_count:n {#1} / 3} +} +\cs_generate_variant:Nn \spath_length:n {V} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_reallength:Nn, +% \spath_greallength:Nn +% } +% The real length of a path is the number of triples that actually draw something (that is, the number of lines, curves, and closepaths). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_reallength:n #1 +{ + \group_begin: + \int_set:Nn \l_@@_tmpa_int {0} + \tl_map_inline:nn {#1} { + \tl_set:Nn \l_@@_tmpc_tl {##1} + \tl_case:NnT \l_@@_tmpc_tl + { + \c_spath_lineto_tl {} + \c_spath_curveto_tl {} + \c_spath_closepath_tl {} + } + { + \int_incr:N \l_@@_tmpa_int + } + } + \int_gzero:N \g_@@_output_int + \int_gset_eq:NN \g_@@_output_int \l_@@_tmpa_int + \group_end: +} +\cs_new_protected_nopar:Npn \spath_reallength:Nn #1#2 +{ + \@@_reallength:n {#2} + \int_set_eq:NN #1 \g_@@_output_int + \int_gzero:N \g_@@_output_int +} +\cs_generate_variant:Nn \spath_reallength:Nn {NV, cn, cV, Nv, cv} +\cs_new_protected_nopar:Npn \spath_greallength:Nn #1#2 +{ + \@@_reallength:n {#2} + \int_gset_eq:NN #1 \g_@@_output_int + \int_gzero:N \g_@@_output_int +} +\cs_generate_variant:Nn \spath_greallength:Nn {NV, cn, cV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_numberofcomponents:Nn, +% \spath_gnumberofcomponents:Nn +% } +% 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_protected_nopar:Npn \@@_numberofcomponents:n #1 +{ + \group_begin: + \int_set:Nn \l_@@_tmpa_int {0} + \tl_map_inline:nn {#1} { + \tl_set:Nn \l_@@_tmpa_tl {##1} + \tl_case:Nn \l_@@_tmpa_tl + { + \c_spath_moveto_tl + { + \int_incr:N \l_@@_tmpa_int + } + } + } + \int_gzero:N \g_@@_output_int + \int_gset_eq:NN \g_@@_output_int \l_@@_tmpa_int + \group_end: +} +\cs_new_protected_nopar:Npn \spath_numberofcomponents:Nn #1#2 +{ + \@@_numberofcomponents:n {#2} + \int_set_eq:NN #1 \g_@@_output_int + \int_gzero:N \g_@@_output_int +} +\cs_generate_variant:Nn \spath_numberofcomponents:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gnumberofcomponents:Nn #1#2 +{ + \@@_numberofcomponents:n {#2} + \int_gset_eq:NN #1 \g_@@_output_int + \int_gzero:N \g_@@_output_int +} +\cs_generate_variant:Nn \spath_gnumberofcomponents:Nn {NV, cn, cV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_initialpoint:Nn, +% \spath_ginitialpoint:Nn +% } +% The starting point of the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_initialpoint:n #1 +{ + \group_begin: + \tl_clear:N \l_@@_tmpb_tl + \tl_set:Nx \l_@@_tmpb_tl + { + { \tl_item:nn {#1} {2} } + { \tl_item:nn {#1} {3} } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_initialpoint:Nn #1#2 +{ + \@@_initialpoint:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_initialpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_ginitialpoint:Nn #1#2 +{ + \@@_initialpoint:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_ginitialpoint:Nn {NV, cn, cV, Nv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_finalpoint:Nn, +% \spath_gfinalpoint:Nn, +% } +% The final point of the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_finalpoint:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_reverse:N \l_@@_tmpa_tl + \tl_clear:N \l_@@_tmpb_tl + \tl_set:Nx \l_@@_tmpb_tl + { + { \tl_item:Nn \l_@@_tmpa_tl {2} } + { \tl_item:Nn \l_@@_tmpa_tl {1} } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_finalpoint:Nn #1#2 +{ + \@@_finalpoint:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_finalpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_gfinalpoint:Nn #1#2 +{ + \@@_finalpoint:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gfinalpoint:Nn {NV, cn, cV, Nv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_reverse:Nn, +% \spath_greverse:Nn +% } +% This computes the reverse of the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_reverse:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + + \tl_clear:N \l_@@_tmpb_tl + \tl_clear:N \l_@@_tmpd_tl + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_left:Nx \l_@@_tmpd_tl + { + {\dim_use:N \l_@@_tmpa_dim} + {\dim_use:N \l_@@_tmpb_dim} + } + + \bool_set_false:N \l_@@_closed_bool + + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} + + \tl_case:NnTF \l_@@_tmpc_tl + { + \c_spath_moveto_tl { + + \bool_if:NT \l_@@_closed_bool + { + \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl + \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl} + \tl_put_right:Nx \l_@@_tmpd_tl + { + { \tl_head:N \l_@@_tmpd_tl } + { \tl_head:N \l_@@_tmpe_tl } + } + } + \bool_set_false:N \l_@@_closed_bool + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl + \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl + \tl_clear:N \l_@@_tmpd_tl + } + \c_spath_lineto_tl { + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_lineto_tl + } + \c_spath_curveto_tl { + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetoa_tl + } + \c_spath_curvetoa_tl { + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curveto_tl + } + \c_spath_curvetob_tl { + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetob_tl + } + } + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_left:Nx \l_@@_tmpd_tl + { + {\dim_use:N \l_@@_tmpa_dim} + {\dim_use:N \l_@@_tmpb_dim} + } + + } + { + \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_closepath_tl + { + \bool_set_true:N \l_@@_closed_bool + } + { + \msg_warning:nnx { spath3 } { unknown path construction } {\l_@@_tmpc_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} + + } + } + + \bool_if:NT \l_@@_closed_bool + { + \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl + \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl} + \tl_put_right:Nx \l_@@_tmpd_tl + { + { \tl_head:N \l_@@_tmpd_tl } + { \tl_head:N \l_@@_tmpe_tl } + } + } + + \bool_set_false:N \l_@@_closed_bool + \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl + \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl + + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_reverse:Nn #1#2 +{ + \@@_reverse:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_reverse:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_reverse:N #1 +{ + \spath_reverse:NV #1#1 +} +\cs_generate_variant:Nn \spath_reverse:N {c} +\cs_new_protected_nopar:Npn \spath_greverse:Nn #1#2 +{ + \@@_reverse:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_greverse:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_greverse:N #1 +{ + \spath_greverse:NV #1#1 +} +\cs_generate_variant:Nn \spath_greverse:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_initialaction:Nn, +% \spath_ginitialaction:Nn, +% } +% This is the first thing that the path does (after the initial move). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_initialaction:n #1 +{ + \group_begin: + \tl_clear:N \l_@@_tmpa_tl + \int_compare:nT + { + \tl_count:n {#1} > 3 + } + { + \tl_set:Nx \l_@@_tmpa_tl + { + \tl_item:Nn {#1} {4} + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_initialaction:Nn #1#2 +{ + \@@_initialaction:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_initialaction:Nn {NV} +\cs_new_protected_nopar:Npn \spath_ginitialaction:Nn #1#2 +{ + \@@_initialaction:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_ginitialaction:Nn {NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_finalaction:Nn, +% \spath_gfinalaction:Nn +% } +% This is the last thing that the path does. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_finalaction:n #1 +{ + \group_begin: + \tl_clear:N \l_@@_tmpb_tl + \int_compare:nT + { + \tl_count:n {#1} > 3 + } + { + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_reverse:N \l_@@_tmpa_tl + \tl_set:Nx \l_@@_tmpb_tl + { + \tl_item:Nn \l_@@_tmpa_tl {3} + } + \tl_if_eq:NNT \l_@@_tmpb_tl \c_spath_curvetoa_tl + { + \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_curveto_tl + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_finalaction:Nn #1#2 +{ + \@@_finalaction:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_finalaction:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gfinalaction:Nn #1#2 +{ + \@@_finalaction:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gfinalaction:Nn {NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_minbb:Nn, +% \spath_gminbb:Nn +% } +% This computes the minimum (bottom left) of the bounding box of the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_minbb:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpa_dim {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_clear:N \l_@@_tmpb_tl + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_use:N \l_@@_tmpa_dim} + {\dim_use:N \l_@@_tmpb_dim} + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_minbb:Nn #1#2 +{ + \@@_minbb:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_minbb:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gminbb:Nn #1#2 +{ + \@@_minbb:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gminbb:Nn {NV, cn, cV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_maxbb:Nn, +% \spath_gmaxbb:Nn, +% } +% This computes the maximum (top right) of the bounding box of the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_maxbb:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpa_dim {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_clear:N \l_@@_tmpb_tl + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_use:N \l_@@_tmpa_dim} + {\dim_use:N \l_@@_tmpb_dim} + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_maxbb:Nn #1#2 +{ + \@@_maxbb:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_maxbb:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gmaxbb:Nn #1#2 +{ + \@@_maxbb:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gmaxbb:Nn {NV, cn, cV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_save_to_aux:Nn, +% \spath_save_to_aux:N +% } +% This saves a soft path to the auxfile. +% The first argument is the macro that will be assigned to the soft path when the aux file is read back in. +% \begin{macrocode} +\int_set:Nn \l_@@_tmpa_int {\char_value_catcode:n {`@}} +\char_set_catcode_letter:N @ +\cs_new_protected_nopar:Npn \spath_save_to_aux:Nn #1#2 { + \tl_if_empty:nF {#2} + { + \tl_clear:N \l_@@_tmpa_tl + \tl_put_right:Nn \l_@@_tmpa_tl { + \ExplSyntaxOn + \tl_clear:N #1 + \tl_set:Nn #1 {#2} + \ExplSyntaxOff + } + \protected@write\@auxout{}{ + \tl_to_str:N \l_@@_tmpa_tl + } + } +} +\char_set_catcode:nn {`@} {\l_@@_tmpa_int} +\cs_generate_variant:Nn \spath_save_to_aux:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_save_to_aux:N #1 +{ + \tl_if_exist:NT #1 + { + \spath_save_to_aux:NV #1#1 + } +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Path Manipulation} +% +% These functions all manipulate a soft path. +% They come with a variety of different argument specifications. +% As a general rule, the first argument is the macro in which to store the modified path, the second is the path to manipulate, and the rest are the information about what to do. +% There is always a variant in which the path is specified by a macro and restored back in that same macro. +% +% +% \begin{macro}{ +% \spath_translate:Nnnn, +% \spath_translate:Nnn, +% \spath_gtranslate:Nnnn, +% \spath_gtranslate:Nnn +% } +% Translates a path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_translate:nnn #1#2#3 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_clear:N \l_@@_tmpb_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl + #2} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl + #3} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_use:N \l_@@_tmpa_dim} + {\dim_use:N \l_@@_tmpb_dim} + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_translate:Nnnn #1#2#3#4 +{ + \@@_translate:nnn {#2}{#3}{#4} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_translate:Nnnn {NVxx, NVVV, NVnn} +\cs_new_protected_nopar:Npn \spath_translate:Nnn #1#2#3 +{ + \spath_translate:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_translate:Nnn {NVV, cnn, cVV} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nnnn #1#2#3#4 +{ + \@@_translate:nnn {#2}{#3}{#4} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gtranslate:Nnnn {NVxx, NVVV, NVnn} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nnn #1#2#3 +{ + \spath_gtranslate:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_gtranslate:Nnn {NVV, cnn, cVV} +% \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_protected_nopar:Npn \spath_translate:Nn #1#2 +{ + \spath_translate:Nnn #1 #2 +} +\cs_generate_variant:Nn \spath_translate:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nn #1#2 +{ + \spath_gtranslate:Nnn #1 #2 +} +\cs_generate_variant:Nn \spath_gtranslate:Nn {NV} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_scale:Nnnn, +% \spath_scale:Nnn, +% \spath_gscale:Nnnn, +% \spath_gscale:Nnn +% } +% Scale a path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_scale:nnn #1#2#3 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_clear:N \l_@@_tmpb_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \fp_set:Nn \l_@@_tmpa_fp {\tl_head:N \l_@@_tmpa_tl * #2} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \fp_set:Nn \l_@@_tmpb_fp {\tl_head:N \l_@@_tmpa_tl * #3} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\fp_to_dim:N \l_@@_tmpa_fp} + {\fp_to_dim:N \l_@@_tmpb_fp} + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_scale:Nnnn #1#2#3#4 +{ + \@@_scale:nnn {#2}{#3}{#4} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_scale:Nnnn {NVnn, Nnxx} +\cs_new_protected_nopar:Npn \spath_scale:Nnn #1#2#3 +{ + \spath_scale:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_scale:Nnn {cnn, cVV, NVV} +\cs_new_protected_nopar:Npn \spath_gscale:Nnnn #1#2#3#4 +{ + \@@_scale:nnn {#2}{#3}{#4} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gscale:Nnnn {NVnn, Nnxx} +\cs_new_protected_nopar:Npn \spath_gscale:Nnn #1#2#3 +{ + \spath_gscale:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_gscale:Nnn {cnn, cVV, NVV} +% \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_protected_nopar:Npn \spath_scale:Nn #1#2 +{ + \spath_scale:Nnn #1 #2 +} + +\cs_generate_variant:Nn \spath_scale:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gscale:Nn #1#2 +{ + \spath_gscale:Nnn #1 #2 +} + +\cs_generate_variant:Nn \spath_gscale:Nn {NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_transform:Nnnnnnnn, +% \spath_transform:Nnnnnnn, +% \spath_gtransform:Nnnnnnnn, +% \spath_gtransform:Nnnnnnn, +% } +% Applies an affine (matrix and vector) transformation to path. +% The matrix is specified in rows first. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_transform:nnnnnnn #1#2#3#4#5#6#7 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_clear:N \l_@@_tmpb_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpd_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \fp_set:Nn \l_@@_tmpa_fp {\l_@@_tmpc_tl * #2 + \l_@@_tmpd_tl * #4 + #6} + \fp_set:Nn \l_@@_tmpb_fp {\l_@@_tmpc_tl * #3 + \l_@@_tmpd_tl * #5 + #7} + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\fp_to_dim:N \l_@@_tmpa_fp} + {\fp_to_dim:N \l_@@_tmpb_fp} + } + } + + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_transform:Nnnnnnnn #1#2#3#4#5#6#7#8 +{ + \@@_transform:nnnnnnn {#2}{#3}{#4}{#5}{#6}{#7}{#8} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_transform:Nnnnnnnn {NVnnnnnn, Nnxxxxxx, cnnnnnnn} +\cs_new_protected_nopar:Npn \spath_transform:Nnnnnnn #1#2#3#4#5#6#7 +{ + \spath_transform:NVnnnnnn #1#1{#2}{#3}{#4}{#5}{#6}{#7} +} +\cs_generate_variant:Nn \spath_transform:Nnnnnnn {cnnnnnn} +\cs_new_protected_nopar:Npn \spath_transform:Nnn #1#2#3 +{ + \spath_transform:Nnnnnnnn #1{#2}#3 +} +\cs_generate_variant:Nn \spath_transform:Nnn {cnn, cVn, NVn, NnV} +\cs_new_protected_nopar:Npn \spath_transform:Nn #1#2 +{ + \spath_transform:NVnnnnnn #1#1#2 +} +\cs_generate_variant:Nn \spath_transform:Nn {cn, cV, NV} + +\cs_new_protected_nopar:Npn \spath_gtransform:Nnnnnnnn #1#2#3#4#5#6#7#8 +{ + \@@_transform:nnnnnnn {#2}{#3}{#4}{#5}{#6}{#7}{#8} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gtransform:Nnnnnnnn {NVnnnnnn, Nnxxxxxx, cnnnnnnn} +\cs_new_protected_nopar:Npn \spath_gtransform:Nnnnnnn #1#2#3#4#5#6#7 +{ + \spath_gtransform:NVnnnnnn #1#1{#2}{#3}{#4}{#5}{#6}{#7} +} +\cs_generate_variant:Nn \spath_gtransform:Nnnnnnn {cnnnnnn} +\cs_new_protected_nopar:Npn \spath_gtransform:Nnn #1#2#3 +{ + \spath_gtransform:Nnnnnnnn #1{#2}#3 +} +\cs_generate_variant:Nn \spath_gtransform:Nnn {cnn, cVn, NVn, NnV} +\cs_new_protected_nopar:Npn \spath_gtransform:Nn #1#2 +{ + \spath_gtransform:NVnnnnnn #1#1#2 +} +\cs_generate_variant:Nn \spath_gtransform:Nn {cn, cV, NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_weld:Nnn, +% \spath_weld:Nn, +% \spath_gweld:Nnn, +% \spath_gweld:Nn +% } +% This welds one path to another, moving the second so that its 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. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_weld:nn #1#2 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nn \l_@@_tmpb_tl {#2} + + \spath_finalpoint:NV \l_@@_tmpc_tl \l_@@_tmpa_tl + \spath_initialpoint:NV \l_@@_tmpd_tl \l_@@_tmpb_tl + + \dim_set:Nn \l_@@_tmpa_dim + { + \tl_item:Nn \l_@@_tmpc_tl {1} + - + \tl_item:Nn \l_@@_tmpd_tl {1} + } + \dim_set:Nn \l_@@_tmpb_dim + { + \tl_item:Nn \l_@@_tmpc_tl {2} + - + \tl_item:Nn \l_@@_tmpd_tl {2} + } + + \spath_translate:NVV \l_@@_tmpb_tl \l_@@_tmpa_dim \l_@@_tmpb_dim + + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl} + } + + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_weld:Nnn #1#2#3 +{ + \@@_weld:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_weld:Nnn {NVV,NVn} +\cs_new_protected_nopar:Npn \spath_weld:Nn #1#2 +{ + \spath_weld:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_weld:Nn {NV, Nv, cV, cv} +\cs_new_protected_nopar:Npn \spath_gweld:Nnn #1#2#3 +{ + \@@_weld:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gweld:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gweld:Nn #1#2 +{ + \spath_gweld:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gweld:Nn {NV, Nv, cV, cv} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_append_no_move:Nnn, +% \spath_append_no_move:Nn, +% \spath_gappend_no_move:Nnn, +% \spath_gappend_no_move:Nn, +% } +% Append the path from the second \Verb+spath+ to the first, removing +% the adjoining move. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_append_no_move:nn #1#2 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nn \l_@@_tmpb_tl {#2} + \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_@@_tmpa_tl \l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_append_no_move:Nnn #1#2#3 +{ + \@@_append_no_move:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_append_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_append_no_move:Nn #1#2 +{ + \spath_append_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_gappend_no_move:Nnn #1#2#3 +{ + \@@_append_no_move:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gappend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gappend_no_move:Nn #1#2 +{ + \spath_gappend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_append:Nnn, +% \spath_append:Nn, +% \spath_gappend:Nnn, +% \spath_gappend:Nn, +% } +% Prepend the path from the second \Verb+spath+ to the first. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_append:Nnn #1#2#3 +{ + \tl_set:Nn #1 {#2} + \tl_put_right:Nn #1 {#3} +} +\cs_generate_variant:Nn \spath_append:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_append:Nn #1#2 +{ + \spath_append:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_append:Nn {NV, Nv} +\cs_new_protected_nopar:Npn \spath_gappend:Nnn #1#2#3 +{ + \tl_gset:Nn #1 {#2} + \tl_gput_right:Nn #1 {#3} +} +\cs_generate_variant:Nn \spath_gappend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gappend:Nn #1#2 +{ + \spath_gappend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_prepend_no_move:Nnn, +% \spath_prepend_no_move:Nn, +% \spath_gprepend_no_move:Nnn, +% \spath_gprepend_no_move:Nn, +% } +% Prepend the path from the second \Verb+spath+ to the first, removing +% the adjoining move. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_prepend_no_move:Nnn #1#2#3 +{ + \spath_append_no_move:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_prepend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_prepend_no_move:Nn #1#2 +{ + \spath_prepend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_prepend_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_gprepend_no_move:Nnn #1#2#3 +{ + \spath_gappend_no_move:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_gprepend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gprepend_no_move:Nn #1#2 +{ + \spath_gprepend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gprepend_no_move:Nn {NV, cv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_prepend:Nnn, +% \spath_prepend:Nn, +% \spath_gprepend:Nnn, +% \spath_gprepend:Nn +% } +% Prepend the path from the second \Verb+spath+ to the first. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_prepend:Nnn #1#2#3 +{ + \spath_append:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_prepend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_prepend:Nn #1#2 +{ + \spath_prepend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_prepend:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gprepend:Nnn #1#2#3 +{ + \spath_gappend:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_gprepend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gprepend:Nn #1#2 +{ + \spath_gprepend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gprepend:Nn {NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_bake_round:Nn, +% \spath_bake_round:N, +% \spath_gbake_round:Nn, +% \spath_gbake_round:N +% } +% +% The corner rounding routine is applied quite late in the process of building a soft path so this ensures that it is done. +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_bake_round:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \pgf@@@@processround \l_@@_tmpa_tl\l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_bake_round:Nn #1#2 +{ + \@@_bake_round:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_bake_round:Nn {NV} +\cs_new_protected_nopar:Npn \spath_bake_round:N #1 +{ + \spath_bake_round:NV #1#1 +} +\cs_generate_variant:Nn \spath_bake_round:N {c} +\cs_new_protected_nopar:Npn \spath_gbake_round:Nn #1#2 +{ + \@@_bake_round:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gbake_round:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gbake_round:N #1 +{ + \spath_gbake_round:NV #1#1 +} +\cs_generate_variant:Nn \spath_gbake_round:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_close:Nn, +% \spath_close:N, +% \spath_gclose:Nn, +% \spath_gclose:N +% } +% Appends a close path to the end of the path. +% For now, the point is the initial or final point (respectively). +% To be future proof, it ought to be the point of the adjacent move to. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_close:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \spath_initialpoint:NV \l_@@_tmpb_tl \l_@@_tmpa_tl + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_closepath_tl + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_close:Nn #1#2 +{ + \@@_close:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_close:Nn {NV} +\cs_new_protected_nopar:Npn \spath_close:N #1 +{ + \spath_close:NV #1#1 +} +\cs_generate_variant:Nn \spath_close:N {c} +\cs_new_protected_nopar:Npn \spath_gclose:Nn #1#2 +{ + \@@_close:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gclose:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gclose:N #1 +{ + \spath_gclose:NV #1#1 +} +\cs_generate_variant:Nn \spath_gclose:N {c} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_open:Nn, +% \spath_open:N, +% \spath_gopen:Nn, +% \spath_gopen:N +% } +% Removes all close paths from the path, replacing them by \Verb+lineto+ if they move any distance. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_open:n #1 +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_clear:N \l_@@_tmpb_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_tmpa_tl + } + { + \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_case:NnF \l_@@_tmpc_tl + { + \c_spath_closepath_tl { + + \bool_if:nF + { + \dim_compare_p:n + { + \l_@@_move_x_dim == \l_@@_tmpa_dim + } + && + \dim_compare_p:n + { + \l_@@_move_y_dim == \l_@@_tmpb_dim + } + } + { + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l_@@_tmpb_tl { + { \dim_use:N \l_@@_move_x_dim } + { \dim_use:N \l_@@_move_y_dim } + } + } + + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + + \c_spath_moveto_tl { + \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl + + \dim_set:Nn \l_@@_move_x_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_move_y_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_right:Nx \l_@@_tmpb_tl { + { \dim_use:N \l_@@_move_x_dim } + { \dim_use:N \l_@@_move_y_dim } + } + + \dim_set_eq:NN \l_@@_tmpa_dim \l_@@_move_x_dim + \dim_set_eq:NN \l_@@_tmpb_dim \l_@@_move_y_dim + } + } + { + \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl + + \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl} + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + + \tl_put_right:Nx \l_@@_tmpb_tl { + { \dim_use:N \l_@@_tmpa_dim } + { \dim_use:N \l_@@_tmpb_dim } + } + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_open:Nn #1#2 +{ + \@@_open:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_open:Nn {NV} +\cs_new_protected_nopar:Npn \spath_open:N #1 +{ + \spath_open:NV #1#1 +} +\cs_new_protected_nopar:Npn \spath_gopen:Nn #1#2 +{ + \@@_open:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gopen:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gopen:N #1 +{ + \spath_gopen:NV #1#1 +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_remove_empty_components:Nn, +% \spath_remove_empty_components:N, +% \spath_gremove_empty_components:Nn, +% \spath_gremove_empty_components:N +% } +% Remove any component that is simply a moveto. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_remove_empty_components:n #1 +{ + \group_begin: + \spath_components_to_seq:Nn \l_@@_tmpa_seq {#1} + \tl_clear:N \l_@@_tmpa_tl + \seq_map_inline:Nn \l_@@_tmpa_seq + { + \int_compare:nF + { + \tl_count:n {##1} == 3 + } + { + \tl_put_right:Nn \l_@@_tmpa_tl {##1} + } + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_remove_empty_components:Nn #1#2 +{ + \@@_remove_empty_components:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_remove_empty_components:Nn {NV} +\cs_new_protected_nopar:Npn \spath_remove_empty_components:N #1 +{ + \spath_remove_empty_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_remove_empty_components:N {c} +\cs_new_protected_nopar:Npn \spath_gremove_empty_components:Nn #1#2 +{ + \@@_remove_empty_components:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gremove_empty_components:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gremove_empty_components:N #1 +{ + \spath_gremove_empty_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_gremove_empty_components:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\spath_if_eq:nn} +% Test if two soft paths are equal, we allow a little tolerance on the calculations. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \spath_if_eq:nn #1#2 { T, F, TF } +{ + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nn \l_@@_tmpb_tl {#2} + \bool_gset_true:N \g_@@_tmpa_bool + \int_compare:nNnTF {\tl_count:N \l_@@_tmpa_tl} = {\tl_count:N \l_@@_tmpb_tl} + { + \int_step_inline:nnnn {1} {3} {\tl_count:N \l_@@_tmpa_tl} + { + \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpa_tl {##1}} + \tl_set:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpb_tl {##1}} + \tl_if_eq:NNF \l_@@_tmpc_tl \l_@@_tmpd_tl + { + \bool_gset_false:N \g_@@_tmpa_bool + } + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpa_tl {##1+1}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpb_tl {##1+1}} + \dim_compare:nF { \dim_abs:n { \l_@@_tmpa_dim - \l_@@_tmpb_dim} < 0.001pt } + { + \bool_gset_false:N \g_@@_tmpa_bool + } + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpa_tl {##1+2}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpb_tl {##1+2}} + \dim_compare:nF { \dim_abs:n { \l_@@_tmpa_dim - \l_@@_tmpb_dim} < 0.001pt } + { + \bool_gset_false:N \g_@@_tmpa_bool + } + } + } + { + \bool_gset_false:N \g_@@_tmpa_bool + } + \group_end: + \bool_if:NTF \g_@@_tmpa_bool + { + \prg_return_true: + } + { + \prg_return_false: + } +} +\prg_generate_conditional_variant:Nnn \spath_if_eq:nn {VV, Vn, nV, vv} {TF, T, F} +% \end{macrocode} +% \end{macro} +% +% \subsection{Splitting Commands} +% +% \begin{macro}{ +% \spath_split_curve:NNnn, +% \spath_gsplit_curve:NNnn +% } +% Splits a Bezier cubic into pieces, storing the pieces in the first two arguments. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_split_curve:nn #1#2 +{ + \group_begin: + \tl_set_eq:NN \l_@@_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl { + {\tl_item:nn {#1} {2}} + {\tl_item:nn {#1} {3}} + } + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curvetoa_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } + + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curvetob_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {2} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {5} + (#2)^2 * \tl_item:nn {#1} {8} + }} + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {3} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {6} + (#2)^2 * \tl_item:nn {#1} {9} + }} + } + + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {2} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {5} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {8} + (#2)^3 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {3} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {6} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {9} + (#2)^3 * \tl_item:nn {#1} {12} + }} + } + + \tl_gclear:N \g_@@_output_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpa_tl + + \tl_clear:N \l_@@_tmpa_tl + \tl_set_eq:NN \l_@@_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {2} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {5} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {8} + (#2)^3 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {3} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {6} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {9} + (#2)^3 * \tl_item:nn {#1} {12} + }} + } + + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curvetoa_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {5} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {8} + (#2)^2 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {6} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {9} + (#2)^2 * \tl_item:nn {#1} {12} + }} + } + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curvetob_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {8} + (#2) * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {9} + (#2) * \tl_item:nn {#1} {12} + }} + } + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_curveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl { + {\tl_item:nn {#1} {11}} + {\tl_item:nn {#1} {12}} + } + + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_curve:NNnn #1#2#3#4 +{ + \@@_split_curve:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_curve:NNnn {NNnV, NNVn, NNVV} +\cs_new_protected_nopar:Npn \spath_gsplit_curve:NNnn #1#2#3#4 +{ + \@@_split_curve:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_curve:NNnn {NNnV, NNVn, NNVV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_split_line:NNnn, +% \spath_gsplit_line:NNnn +% } +% Splits a line segment. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_split_line:nn #1#2 +{ + \group_begin: + \tl_set_eq:NN \l_@@_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl { + {\tl_item:nn {#1} {2}} + {\tl_item:nn {#1} {3}} + } + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } + \tl_gclear:N \g_@@_output_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpa_tl + + \tl_clear:N \l_@@_tmpa_tl + \tl_set_eq:NN \l_@@_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx \l_@@_tmpa_tl { + {\tl_item:nn {#1} {5}} + {\tl_item:nn {#1} {6}} + } + + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_line:NNnn #1#2#3#4 +{ + \@@_split_line:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_line:NNnn {NNnV, NNVn, NNVV} +\cs_new_protected_nopar:Npn \spath_gsplit_line:NNnn #1#2#3#4 +{ + \@@_split_line:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_line:NNnn {NNnV, NNVn, NNVV} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\int_new:N \l_@@_split_int +\int_new:N \l_@@_splitat_int +\fp_new:N \l_@@_split_fp +\bool_new:N \l_@@_split_bool +\tl_new:N \l_@@_split_path_tl +\tl_new:N \l_@@_split_patha_tl +\tl_new:N \l_@@_split_pathb_tl +\tl_new:N \l_@@_split_intoa_tl +\tl_new:N \l_@@_split_intob_tl +\dim_new:N \l_@@_splitx_dim +\dim_new:N \l_@@_splity_dim +% \end{macrocode} +% +% \begin{macro}{ +% \spath_split_at:NNnn, +% \spath_split_at:Nnn, +% \spath_split_at:Nn, +% \spath_gsplit_at:NNnn +% \spath_gsplit_at:Nnn, +% \spath_gsplit_at:Nn +% } +% Split a path according to the parameter generated by the intersection routine. +% The versions with two \texttt{N} arguments stores the two parts in two macros, the version with a single \texttt{N} joins them back into a single path (as separate components). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_split_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l_@@_splitat_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l_@@_split_fp {#2 - floor(#2)} + + % Is split point near one end or other of a component? + \fp_compare:nT + { + \l_@@_split_fp < 0.01 + } + { + % Near the start, so we'll place it at the start + \fp_set:Nn \l_@@_split_fp {0} + } + \fp_compare:nT + { + \l_@@_split_fp > 0.99 + } + { + % Near the end, so we'll place it at the end + \fp_set:Nn \l_@@_split_fp {0} + \int_incr:N \l_@@_splitat_int + } + + \int_zero:N \l_@@_split_int + \bool_set_true:N \l_@@_split_bool + + \tl_set:Nn \l_@@_split_path_tl {#1} + \tl_clear:N \l_@@_split_patha_tl + + \dim_zero:N \l_@@_splitx_dim + \dim_zero:N \l_@@_splity_dim + + \bool_until_do:nn { + \tl_if_empty_p:N \l_@@_split_path_tl + || + \int_compare_p:n { \l_@@_splitat_int == \l_@@_split_int } + } + { + \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_split_path_tl} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + \tl_case:Nn \l_@@_tmpc_tl + { + \c_spath_lineto_tl + { + \int_incr:N \l_@@_split_int + } + \c_spath_curvetoa_tl + { + \int_incr:N \l_@@_split_int + } + } + \int_compare:nT { \l_@@_split_int < \l_@@_splitat_int } + { + \tl_put_right:NV \l_@@_split_patha_tl \l_@@_tmpc_tl + + \tl_put_right:Nx \l_@@_split_patha_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \dim_set:Nn \l_@@_splitx_dim {\tl_head:N \l_@@_split_path_tl} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \tl_put_right:Nx \l_@@_split_patha_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \dim_set:Nn \l_@@_splity_dim {\tl_head:N \l_@@_split_path_tl} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + } + } + + \tl_clear:N \l_@@_split_pathb_tl + \tl_put_right:NV \l_@@_split_pathb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l_@@_split_pathb_tl + { + {\dim_use:N \l_@@_splitx_dim} + {\dim_use:N \l_@@_splity_dim} + } + + \fp_compare:nTF + { + \l_@@_split_fp == 0 + } + { + \tl_set_eq:NN \l_@@_split_intob_tl \l_@@_split_pathb_tl + \tl_if_empty:NF \l_@@_split_path_tl + { + \tl_put_right:NV \l_@@_split_intob_tl \l_@@_tmpc_tl + \tl_put_right:NV \l_@@_split_intob_tl \l_@@_split_path_tl + } + } + { + + \tl_case:Nn \l_@@_tmpc_tl + { + \c_spath_lineto_tl + { + \tl_put_right:NV \l_@@_split_pathb_tl \l_@@_tmpc_tl + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \spath_split_line:NNVV + \l_@@_split_intoa_tl + \l_@@_split_intob_tl + \l_@@_split_pathb_tl + \l_@@_split_fp + + \prg_replicate:nn {3} { + \tl_set:Nx \l_@@_split_intoa_tl {\tl_tail:N \l_@@_split_intoa_tl} + } + + \tl_put_right:NV \l_@@_split_patha_tl \l_@@_split_intoa_tl + \tl_put_right:NV \l_@@_split_intob_tl \l_@@_split_path_tl + } + \c_spath_curvetoa_tl + { + \tl_put_right:NV \l_@@_split_pathb_tl \l_@@_tmpc_tl + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \prg_replicate:nn {2} { + + \tl_put_right:Nx \l_@@_split_pathb_tl + { \tl_head:N \l_@@_split_path_tl } + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + + \tl_put_right:Nx \l_@@_split_pathb_tl + {{ \tl_head:N \l_@@_split_path_tl }} + \tl_set:Nx \l_@@_split_path_tl {\tl_tail:N \l_@@_split_path_tl } + } + + \spath_split_curve:NNVV + \l_@@_split_intoa_tl + \l_@@_split_intob_tl + \l_@@_split_pathb_tl \l_@@_split_fp + + \prg_replicate:nn {3} { + \tl_set:Nx \l_@@_split_intoa_tl {\tl_tail:N \l_@@_split_intoa_tl} + } + + \tl_put_right:NV \l_@@_split_patha_tl \l_@@_split_intoa_tl + \tl_put_right:NV \l_@@_split_intob_tl \l_@@_split_path_tl + } + } + } + + \tl_gclear:N \g_@@_output_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_split_patha_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_split_intob_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_at:NNnn #1#2#3#4 +{ + \@@_split_at:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_at:NNnn {NNVn, NNVV, NNnV} +\cs_new_protected_nopar:Npn \spath_gsplit_at:NNnn #1#2#3#4 +{ + \@@_split_at:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at:NNnn {NNVn, NNVV, NNnV} +% \end{macrocode} +% +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_split_at:Nnn #1#2#3 +{ + \@@_split_at:nn {#2}{#3} + \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1} \tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_at:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_split_at:Nn #1#2 +{ + \spath_split_at:NVn #1#1{#2} +} +\cs_new_protected_nopar:Npn \spath_gsplit_at:Nnn #1#2#3 +{ + \@@_split_at:nn {#2}{#3} + \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1} \tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_gsplit_at:Nn #1#2 +{ + \spath_gsplit_at:NVn #1#1{#2} +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Shortening Paths} +% +% This code relates to shortening paths. +% For curved paths, the routine uses the derivative at the end to figure out how far back to shorten. +% This means that the actual length that it shortens by is approximate, but it is guaranteed to be along its length. +% +% As in the previous section, there are various versions. +% In particular, there are versions where the path can be specified by a macro and is saved back into that macro. +% +% \begin{macrocode} +\tl_new:N \l_@@_shorten_fa_tl +\tl_new:N \l_@@_shorten_path_tl +\tl_new:N \l_@@_shorten_last_tl +\tl_new:N \l_@@_shorten_lasta_tl +\tl_new:N \l_@@_shorten_lastb_tl +\int_new:N \l_@@_shorten_int +\fp_new:N \l_@@_shorten_x_fp +\fp_new:N \l_@@_shorten_y_fp +\fp_new:N \l_@@_shorten_len_fp +% \end{macrocode} +% +% \begin{macro}{ +% \spath_shorten_at_end:Nnn +% } +% This macro shortens a path from the end by a dimension. +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_shorten_at_end:nn #1#2 +{ + \int_compare:nTF + { + \tl_count:n {#1} > 3 + } + { + \group_begin: + \tl_set:Nn \l_@@_shorten_path_tl {#1} + \tl_reverse:N \l_@@_shorten_path_tl + + \tl_set:Nx \l_@@_shorten_fa_tl {\tl_item:Nn \l_@@_shorten_path_tl {3}} + + \tl_clear:N \l_@@_shorten_last_tl + \tl_if_eq:NNTF \l_@@_shorten_fa_tl \c_spath_curveto_tl + { + \int_set:Nn \l_@@_shorten_int {3} + } + { + \int_set:Nn \l_@@_shorten_int {1} + } + + \prg_replicate:nn { \l_@@_shorten_int } + { + \tl_put_right:Nx \l_@@_shorten_last_tl + { + {\tl_head:N \l_@@_shorten_path_tl} + } + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl} + \tl_put_right:Nx \l_@@_shorten_last_tl + { + {\tl_head:N \l_@@_shorten_path_tl} + } + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl} + \tl_put_right:Nx \l_@@_shorten_last_tl + { + \tl_head:N \l_@@_shorten_path_tl + } + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl} + } + + \tl_put_right:Nx \l_@@_shorten_last_tl + { + {\tl_item:Nn \l_@@_shorten_path_tl {1}} + {\tl_item:Nn \l_@@_shorten_path_tl {2}} + } + \tl_put_right:NV \l_@@_shorten_last_tl \c_spath_moveto_tl + + \tl_reverse:N \l_@@_shorten_path_tl + + \fp_set:Nn \l_@@_shorten_x_fp + { + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {4}} + - + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {1}} + } + + \fp_set:Nn \l_@@_shorten_y_fp + { + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {5}} + - + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {2}} + } + + \fp_set:Nn \l_@@_shorten_len_fp + { + sqrt( \l_@@_shorten_x_fp * \l_@@_shorten_x_fp + \l_@@_shorten_y_fp * \l_@@_shorten_y_fp ) + } + + \fp_compare:nTF + { + \l_@@_shorten_len_fp > #2 + } + { + + \fp_set:Nn \l_@@_shorten_len_fp + { + (\l_@@_shorten_len_fp - #2)/ \l_@@_shorten_len_fp + } + + \tl_reverse:N \l_@@_shorten_last_tl + + \tl_if_eq:NNTF \l_@@_shorten_fa_tl \c_spath_curveto_tl + { + \fp_set:Nn \l_@@_shorten_len_fp + { + 1 - (1 -\l_@@_shorten_len_fp)/3 + } + \spath_split_curve:NNVV + \l_@@_shorten_lasta_tl + \l_@@_shorten_lastb_tl + \l_@@_shorten_last_tl + \l_@@_shorten_len_fp + } + { + \spath_split_line:NNVV + \l_@@_shorten_lasta_tl + \l_@@_shorten_lastb_tl + \l_@@_shorten_last_tl + \l_@@_shorten_len_fp + } + + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_shorten_lasta_tl {\tl_tail:N \l_@@_shorten_lasta_tl} + } + + \tl_put_right:NV \l_@@_shorten_path_tl \l_@@_shorten_lasta_tl + + } + { + + \int_compare:nT + { + \tl_count:N \l_@@_shorten_path_tl > 3 + } + { + \dim_set:Nn \l_@@_tmpa_dim {\fp_to_dim:n {#2 - \l_@@_shorten_len_fp } } + \spath_shorten_at_end:NV \l_@@_shorten_path_tl \l_@@_tmpa_dim + } + } + + \tl_gset_eq:NN \g_@@_output_tl \l_@@_shorten_path_tl + \group_end: + } + { + \tl_gset:Nn \g_@@_output_tl {#1} + } +} +\cs_new_protected_nopar:Npn \spath_shorten_at_end:Nnn #1#2#3 +{ + \@@_shorten_at_end:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_shorten_at_end:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_shorten_at_end:Nn #1#2 +{ + \spath_shorten_at_end:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_shorten_at_end:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_gshorten_at_end:Nnn #1#2#3 +{ + \@@_shorten_at_end:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gshorten_at_end:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_gshorten_at_end:Nn #1#2 +{ + \spath_gshorten_at_end:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gshorten_at_end:Nn {cn, cV, NV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_shorten_at_start:Nnn, +% \spath_shorten_at_start:Nn, +% \spath_gshorten_at_start:Nnn, +% \spath_gshorten_at_start:Nn +% } +% +% This macro shortens a path from the start by a dimension. +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_shorten_at_start:nn #1#2 +{ + \int_compare:nTF + { + \tl_count:n {#1} > 3 + } + { + \group_begin: + \tl_set:Nn \l_@@_shorten_path_tl {#1} + + \tl_set:Nx \l_@@_shorten_fa_tl {\tl_item:Nn \l_@@_shorten_path_tl {4}} + + \tl_clear:N \l_@@_shorten_last_tl + + \tl_if_eq:NNTF \l_@@_shorten_fa_tl \c_spath_curvetoa_tl + { + \int_set:Nn \l_@@_shorten_int {3} + } + { + \int_set:Nn \l_@@_shorten_int {1} + } + + \tl_set_eq:NN \l_@@_shorten_last_tl \c_spath_moveto_tl + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl } + + \prg_replicate:nn { \l_@@_shorten_int } + { + \@@_tl_put_right_braced:Nx \l_@@_shorten_last_tl {\tl_item:Nn \l_@@_shorten_path_tl {1}} + \@@_tl_put_right_braced:Nx \l_@@_shorten_last_tl {\tl_item:Nn \l_@@_shorten_path_tl {2}} + \tl_put_right:Nx \l_@@_shorten_last_tl {\tl_item:Nn \l_@@_shorten_path_tl {3}} + + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl } + } + } + \@@_tl_put_right_braced:Nx \l_@@_shorten_last_tl {\tl_item:Nn \l_@@_shorten_path_tl {1}} + \@@_tl_put_right_braced:Nx \l_@@_shorten_last_tl {\tl_item:Nn \l_@@_shorten_path_tl {2}} + + \fp_set:Nn \l_@@_shorten_x_fp + { + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {5}} + - + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {2}} + } + + \fp_set:Nn \l_@@_shorten_y_fp + { + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {6}} + - + \dim_to_fp:n {\tl_item:Nn \l_@@_shorten_last_tl {3}} + } + + \fp_set:Nn \l_@@_shorten_len_fp + { + sqrt( \l_@@_shorten_x_fp * \l_@@_shorten_x_fp + \l_@@_shorten_y_fp * \l_@@_shorten_y_fp ) + } + + \fp_compare:nTF + { + \l_@@_shorten_len_fp > #2 + } + { + + \fp_set:Nn \l_@@_shorten_len_fp + { + #2/ \l_@@_shorten_len_fp + } + + \tl_if_eq:NNTF \l_@@_shorten_fa_tl \c_spath_curvetoa_tl + { + \fp_set:Nn \l_@@_shorten_len_fp + { + \l_@@_shorten_len_fp/3 + } + \spath_split_curve:NNVV + \l_@@_shorten_lasta_tl + \l_@@_shorten_lastb_tl + \l_@@_shorten_last_tl + \l_@@_shorten_len_fp + } + { + \spath_split_line:NNVV + \l_@@_shorten_lasta_tl + \l_@@_shorten_lastb_tl + \l_@@_shorten_last_tl + \l_@@_shorten_len_fp + } + + \prg_replicate:nn {2} + { + \tl_set:Nx \l_@@_shorten_path_tl {\tl_tail:N \l_@@_shorten_path_tl} + } + + \tl_put_left:NV \l_@@_shorten_path_tl \l_@@_shorten_lastb_tl + + } + { + + \tl_put_left:NV \l_@@_shorten_path_tl \c_spath_moveto_tl + + \int_compare:nT + { + \tl_count:N \l_@@_shorten_path_tl > 3 + } + { + \dim_set:Nn \l_@@_tmpa_dim {\fp_to_dim:n {#2 - \l_@@_shorten_len_fp } } + \spath_shorten_at_start:NV \l_@@_shorten_path_tl \l_@@_tmpa_dim + } + } + + \tl_gset_eq:NN \g_@@_output_tl \l_@@_shorten_path_tl + \group_end: + } + { + \tl_gset:Nn \g_@@_output_tl {#1} + } +} +\cs_new_protected_nopar:Npn \spath_shorten_at_start:Nnn #1#2#3 +{ + \@@_shorten_at_start:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_shorten_at_start:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_shorten_at_start:Nn #1#2 +{ + \spath_shorten_at_start:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_shorten_at_start:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_gshorten_at_start:Nnn #1#2#3 +{ + \@@_shorten_at_start:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gshorten_at_start:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_gshorten_at_start:Nn #1#2 +{ + \spath_gshorten_at_start:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gshorten_at_start:Nn {cn, cV, NV} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Points on a Path} +% +% \begin{macro}{ +% \spath_point_at:Nnn, +% \spath_gpoint_at:Nnn, +% } +% +% Get the location of a point on a path, using the same location specification as the intersection library. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_point_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l_@@_tmpa_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l_@@_tmpa_fp {#2 - floor(#2)} + + \spath_segments_to_seq:Nn \l_@@_tmpa_seq {#1} + + \int_compare:nTF + { + \l_@@_tmpa_int < 1 + } + { + \spath_initialpoint:Nn \l_@@_tmpc_tl {#1} + } + { + \int_compare:nTF + { + \l_@@_tmpa_int > \seq_count:N \l_@@_tmpa_seq + } + { + \spath_finalpoint:Nn \l_@@_tmpc_tl {#1} + } + { + + \tl_set:Nx \l_@@_tmpa_tl {\seq_item:Nn \l_@@_tmpa_seq { \l_@@_tmpa_int} } + + \int_compare:nTF + { + \tl_count:N \l_@@_tmpa_tl > 3 + } + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {4}} + } + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {1}} + } + + \tl_clear:N \l_@@_tmpc_tl + + \tl_case:Nn \l_@@_tmpb_tl + { + \c_spath_moveto_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + { + \tl_item:Nn \l_@@_tmpa_tl {2} + } + { + \tl_item:Nn \l_@@_tmpa_tl {3} + } + } + } + + \c_spath_lineto_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp) * ( \tl_item:Nn \l_@@_tmpa_tl {2} ) + + + \l_@@_tmpa_fp * ( \tl_item:Nn \l_@@_tmpa_tl {5} ) + } + } + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp) * ( \tl_item:Nn \l_@@_tmpa_tl {3} ) + + + \l_@@_tmpa_fp * ( \tl_item:Nn \l_@@_tmpa_tl {6} ) + } + } + } + } + + \c_spath_closepath_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp) * ( \tl_item:Nn \l_@@_tmpa_tl {2} ) + + + \l_@@_tmpa_fp * ( \tl_item:Nn \l_@@_tmpa_tl {5} ) + } + } + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp) * ( \tl_item:Nn \l_@@_tmpa_tl {3} ) + + + \l_@@_tmpa_fp * ( \tl_item:Nn \l_@@_tmpa_tl {6} ) + } + } + } + } + + \c_spath_curvetoa_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp)^3 * \tl_item:Nn \l_@@_tmpa_tl {2} + 3 * (1 - \l_@@_tmpa_fp)^2 * (\l_@@_tmpa_fp) * \tl_item:Nn \l_@@_tmpa_tl {5} + 3 * (1 - \l_@@_tmpa_fp) * (\l_@@_tmpa_fp)^2 * \tl_item:Nn \l_@@_tmpa_tl {8} + (\l_@@_tmpa_fp)^3 * \tl_item:Nn \l_@@_tmpa_tl {11} + }} + {\fp_to_dim:n + { + (1 - \l_@@_tmpa_fp)^3 * \tl_item:Nn \l_@@_tmpa_tl {3} + 3 * (1 - \l_@@_tmpa_fp)^2 * (\l_@@_tmpa_fp) * \tl_item:Nn \l_@@_tmpa_tl {6} + 3 * (1 - \l_@@_tmpa_fp) * (\l_@@_tmpa_fp)^2 * \tl_item:Nn \l_@@_tmpa_tl {9} + (\l_@@_tmpa_fp)^3 * \tl_item:Nn \l_@@_tmpa_tl {12} + }} + } + } + } + } + } + + \tl_gclear:N \g_@@_output_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpc_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_point_at:Nnn #1#2#3 +{ + \@@_point_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_point_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \spath_gpoint_at:Nnn #1#2#3 +{ + \@@_point_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gpoint_at:Nnn {NVn, NVV, NnV} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_tangent_at:Nnn, +% \spath_gtangent_at:Nnn, +% } +% +% Get the tangent at a point on a path, using the same location specification as the intersection library. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_tangent_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l_@@_tmpa_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l_@@_tmpa_fp {#2 - floor(#2)} + + \spath_segments_to_seq:Nn \l_@@_tmpa_seq {#1} + + \int_compare:nTF + { + \l_@@_tmpa_int < 1 + } + { + \spath_initialpoint:Nn \l_@@_tmpc_tl {#1} + } + { + \int_compare:nTF + { + \l_@@_tmpa_int > \seq_count:N \l_@@_tmpa_seq + } + { + \spath_finalpoint:Nn \l_@@_tmpc_tl {#1} + } + { + + \tl_set:Nx \l_@@_tmpa_tl {\seq_item:Nn \l_@@_tmpa_seq { \l_@@_tmpa_int} } + + \int_compare:nTF + { + \tl_count:N \l_@@_tmpa_tl > 3 + } + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {4}} + } + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {1}} + } + + \tl_clear:N \l_@@_tmpc_tl + + \tl_case:Nn \l_@@_tmpb_tl + { + \c_spath_moveto_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + { + \tl_item:Nn \l_@@_tmpa_tl {2} + } + { + \tl_item:Nn \l_@@_tmpa_tl {3} + } + } + } + + \c_spath_lineto_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + ( \tl_item:Nn \l_@@_tmpa_tl {5} ) + - + ( \tl_item:Nn \l_@@_tmpa_tl {2} ) + } + } + {\fp_to_dim:n + { + ( \tl_item:Nn \l_@@_tmpa_tl {6} ) + - + ( \tl_item:Nn \l_@@_tmpa_tl {3} ) + } + } + } + } + + \c_spath_closepath_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + ( \tl_item:Nn \l_@@_tmpa_tl {5} ) + - + ( \tl_item:Nn \l_@@_tmpa_tl {2} ) + } + } + {\fp_to_dim:n + { + ( \tl_item:Nn \l_@@_tmpa_tl {6} ) + - + ( \tl_item:Nn \l_@@_tmpa_tl {3} ) + } + } + } + } + + \c_spath_curvetoa_tl + { + \tl_set:Nx \l_@@_tmpc_tl + { + {\fp_to_dim:n + { + 3*(1 - \l_@@_tmpa_fp)^2 * (\tl_item:Nn \l_@@_tmpa_tl {5} - \tl_item:Nn \l_@@_tmpa_tl {2}) + + 6 * (1 - \l_@@_tmpa_fp) * (\l_@@_tmpa_fp) * (\tl_item:Nn \l_@@_tmpa_tl {8} - \tl_item:Nn \l_@@_tmpa_tl {5}) + + 3*(\l_@@_tmpa_fp)^2 * (\tl_item:Nn \l_@@_tmpa_tl {11} - \tl_item:Nn \l_@@_tmpa_tl {8}) + } + } + {\fp_to_dim:n + { + 3*(1 - \l_@@_tmpa_fp)^2 * (\tl_item:Nn \l_@@_tmpa_tl {6} - \tl_item:Nn \l_@@_tmpa_tl {3}) + + 6 * (1 - \l_@@_tmpa_fp) * (\l_@@_tmpa_fp) * (\tl_item:Nn \l_@@_tmpa_tl {9} - \tl_item:Nn \l_@@_tmpa_tl {6}) + + 3*(\l_@@_tmpa_fp)^2 * (\tl_item:Nn \l_@@_tmpa_tl {12} - \tl_item:Nn \l_@@_tmpa_tl {9}) + }} + } + } + } + } + } + + \tl_gclear:N \g_@@_output_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpc_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_tangent_at:Nnn #1#2#3 +{ + \@@_tangent_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_tangent_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \spath_gtangent_at:Nnn #1#2#3 +{ + \@@_tangent_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gtangent_at:Nnn {NVn, NVV, NnV} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_transformation_at:Nnn, +% \spath_gtransformation_at:Nnn +% } +% Gets a transformation that will align to a point on the path with the x-axis along the path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_transformation_at:nn #1#2 +{ + \group_begin: + \tl_clear:N \l_@@_tmpa_tl + \@@_tangent_at:nn {#1}{#2} + \tl_set_eq:NN \l_@@_tmpb_tl \g_@@_output_tl + \fp_set:Nn \l_@@_tmpa_fp { sqrt( (\tl_item:Nn \l_@@_tmpb_tl {1})^2 + (\tl_item:Nn \l_@@_tmpb_tl {2})^2 ) } + \fp_compare:nTF {\l_@@_tmpa_fp = 0} + { + \fp_set:Nn \l_@@_tmpa_fp {1} + \fp_set:Nn \l_@@_tmpb_fp {0} + } + { + \fp_set:Nn \l_@@_tmpb_fp { (\tl_item:Nn \l_@@_tmpb_tl {2}) / \l_@@_tmpa_fp } + \fp_set:Nn \l_@@_tmpa_fp { (\tl_item:Nn \l_@@_tmpb_tl {1}) / \l_@@_tmpa_fp } + } + \tl_set:Nx \l_@@_tmpa_tl + { + { \fp_to_decimal:n { \l_@@_tmpa_fp } } + { \fp_to_decimal:n { \l_@@_tmpb_fp } } + { \fp_to_decimal:n {- \l_@@_tmpb_fp } } + { \fp_to_decimal:n { \l_@@_tmpa_fp } } + } + \@@_point_at:nn {#1}{#2} + \tl_put_right:NV \l_@@_tmpa_tl \g_@@_output_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_transformation_at:Nnn #1#2#3 +{ + \@@_transformation_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_transformation_at:Nnn {NVn, NVV, NnV, NvV} +\cs_new_protected_nopar:Npn \spath_gtransformation_at:Nnn #1#2#3 +{ + \@@_transformation_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gtransformation_at:Nnn {NVn, NVV, NnV} +% \end{macrocode} +% \end{macro} +% +% \subsection{Intersection Routines} +% +% Note: I'm not consistent with number schemes. +% The intersection library is 0-based, but the user interface is 1-based (since if we ``count'' in a \Verb+\foreach+ then it starts at 1). +% This should be more consistent. +% +% \begin{macrocode} +\tl_new:N \l_@@_split_path_a_tl +\tl_new:N \l_@@_split_path_b_tl +\tl_new:N \l_@@_split_path_a_start_tl +\tl_new:N \l_@@_split_path_b_start_tl +\tl_new:N \l_@@_split_path_a_end_tl +\tl_new:N \l_@@_split_path_b_end_tl +\tl_new:N \l_@@_split_path_a_final_tl +\tl_new:N \l_@@_split_path_b_final_tl + +\tl_new:N \l_@@_split_prev_first_tl +\tl_new:N \l_@@_split_prev_second_tl + +\seq_new:N \l_@@_split_first_seq +\seq_new:N \l_@@_split_second_seq + +\int_new:N \l_@@_split_segment_int +% \end{macrocode} +% +% \begin{macro}{ +% \spath_intersect:NN, +% \spath_intersect:nn, +% } +% Pass two spaths to pgf's intersection routine. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_intersect:NN #1#2 +{ + \pgfintersectionofpaths% + {% + \pgfsetpath #1 + }{% + \pgfsetpath #2 + } +} +\tl_new:N \l_@@_intersecta_tl +\tl_new:N \l_@@_intersectb_tl +\cs_new_protected_nopar:Npn \spath_intersect:nn #1#2 +{ + \tl_set:Nn \l_@@_intersecta_tl {#1} + \tl_set:Nn \l_@@_intersectb_tl {#2} + \spath_intersect:NN \l_@@_intersecta_tl \l_@@_intersectb_tl +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_split_at_intersections:NNnn, +% \spath_split_at_intersections:NN, +% \spath_gsplit_at_intersections:NNnn, +% \spath_gsplit_at_intersections:NN +% } +% Given two paths, split them at points where they intersect and store them in the macros. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_split_at_intersections:nn #1#2 +{ + \group_begin: + + % Clear some token lists and sequences + \tl_clear:N \l_@@_split_path_a_final_tl + \tl_clear:N \l_@@_split_path_b_final_tl + \seq_clear:N \l_@@_split_first_seq + \seq_clear:N \l_@@_split_second_seq + + \pgfintersectionsortbyfirstpath + % Find the intersections of these segments + \tl_set:Nn \l_@@_split_path_a_tl {#1} + \tl_set:Nn \l_@@_split_path_b_tl {#2} + % Remove empty components +% \spath_path_remove_empty_components:N \l_@@_split_path_a_tl +% \spath_path_remove_empty_components:N \l_@@_split_path_b_tl + + \spath_intersect:NN \l_@@_split_path_a_tl \l_@@_split_path_b_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfintersectiongetsolutiontimes{##1}{\l_@@_split_first_tl}{\l_@@_split_second_tl} + \seq_put_left:NV \l_@@_split_first_seq \l_@@_split_first_tl + } + } + + \spath_intersect:NN \l_@@_split_path_b_tl \l_@@_split_path_a_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfintersectiongetsolutiontimes{##1}{\l_@@_split_first_tl}{\l_@@_split_second_tl} + \seq_put_left:NV \l_@@_split_second_seq \l_@@_split_first_tl + } + } + + \tl_set:Nn \l_@@_split_prev_first_tl {-1} + + \seq_map_inline:Nn \l_@@_split_first_seq + { + \tl_set:Nn \l_@@_split_first_tl {##1} + + \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_split_first_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l_@@_split_first_tl) } + = + \fp_to_int:n {floor( \l_@@_split_prev_first_tl) } + } + { + \tl_set:Nx \l_@@_split_first_tl + { + \fp_eval:n { + floor( \l_@@_split_first_tl ) + + + ( \l_@@_split_first_tl - floor( \l_@@_split_first_tl) ) + / + ( \l_@@_split_prev_first_tl - floor( \l_@@_split_prev_first_tl) ) + } + } + } + \tl_set_eq:NN \l_@@_split_prev_first_tl \l_@@_tmpa_tl + + \spath_split_at:NNVV \l_@@_split_path_a_start_tl \l_@@_split_path_a_end_tl \l_@@_split_path_a_tl \l_@@_split_first_tl + + \tl_put_left:NV \l_@@_split_path_a_final_tl \l_@@_split_path_a_end_tl + \tl_set_eq:NN \l_@@_split_path_a_tl \l_@@_split_path_a_start_tl + + } + + \tl_set:Nn \l_@@_split_prev_second_tl {-1} + + \seq_map_inline:Nn \l_@@_split_second_seq + { + \tl_set:Nn \l_@@_split_second_tl {##1} + + \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_split_second_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l_@@_split_second_tl) } + = + \fp_to_int:n {floor( \l_@@_split_prev_second_tl) } + } + { + \tl_set:Nx \l_@@_split_second_tl + { + \fp_eval:n { + floor( \l_@@_split_second_tl ) + + + ( \l_@@_split_second_tl - floor( \l_@@_split_second_tl) ) + / + ( \l_@@_split_prev_second_tl - floor( \l_@@_split_prev_second_tl) ) + } + } + } + \tl_set_eq:NN \l_@@_split_prev_second_tl \l_@@_tmpa_tl + + \spath_split_at:NNVV \l_@@_split_path_b_start_tl \l_@@_split_path_b_end_tl \l_@@_split_path_b_tl\l_@@_split_second_tl + + \tl_put_left:NV \l_@@_split_path_b_final_tl \l_@@_split_path_b_end_tl + \tl_set_eq:NN \l_@@_split_path_b_tl \l_@@_split_path_b_start_tl + + } + + \tl_put_left:NV \l_@@_split_path_a_final_tl \l_@@_split_path_a_tl + \tl_put_left:NV \l_@@_split_path_b_final_tl \l_@@_split_path_b_tl + + \tl_if_empty:NT \l_@@_split_path_a_final_tl + { + \tl_set_eq:NN \l_@@_split_path_a_final_tl \l_@@_split_path_a_tl + } + \tl_if_empty:NT \l_@@_split_path_b_final_tl + { + \tl_set_eq:NN \l_@@_split_path_b_final_tl \l_@@_split_path_b_tl + } + + \spath_remove_empty_components:N \l_@@_split_path_a_final_tl + \spath_remove_empty_components:N \l_@@_split_path_b_final_tl + + \tl_gclear:N \g_@@_output_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_split_path_a_final_tl + \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_split_path_b_final_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_at_intersections:NNnn #1#2#3#4 +{ + \@@_split_at_intersections:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_at_intersections:NNnn {NNVV, ccVV, ccvv} +\cs_new_protected_nopar:Npn \spath_split_at_intersections:NN #1#2 +{ + \spath_split_at_intersections:NNVV #1#2#1#2 +} +\cs_generate_variant:Nn \spath_split_at_intersections:NN {cc} +\cs_new_protected_nopar:Npn \spath_gsplit_at_intersections:NNnn #1#2#3#4 +{ + \@@_split_at_intersections:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}} + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at_intersections:NNnn {NNVV, ccVV, ccvv} +\cs_new_protected_nopar:Npn \spath_gsplit_at_intersections:NN #1#2 +{ + \spath_gsplit_at_intersections:NNVV #1#2#1#2 +} +\cs_generate_variant:Nn \spath_gsplit_at_intersections:NN {cc} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_split_at_self_intersections:Nn, +% \spath_split_at_self_intersections:N, +% \spath_gsplit_at_self_intersections:Nn, +% \spath_gsplit_at_self_intersections:N, +% } +% Given a path, split it at points where it self-intersects and store in the given macro. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_split_at_self_intersections:n #1 +{ + \group_begin: + + % Copy the path + \tl_set:Nn \l_@@_split_path_b_tl {#1} + + % Open the path + \spath_open:N \l_@@_split_path_b_tl + % Remove empty components + \spath_remove_empty_components:N \l_@@_split_path_b_tl + % Make a copy for later + \tl_set_eq:NN \l_@@_split_path_b_final_tl \l_@@_split_path_b_tl + + % Clear some token lists and sequences + \tl_clear:N \l_@@_split_path_a_tl + \seq_clear:N \l_@@_split_first_seq + \int_zero:N \l_@@_split_segment_int + + \pgfintersectionsortbyfirstpath + + \bool_do_until:nn + { + \int_compare_p:n + { + \tl_count:N \l_@@_split_path_b_tl < 4 + } + } + { + \tl_clear:N \l_@@_split_path_a_tl + \tl_put_right:Nx \l_@@_split_path_a_tl + { + \tl_item:Nn \l_@@_split_path_b_tl {1} + {\tl_item:Nn \l_@@_split_path_b_tl {2}} + {\tl_item:Nn \l_@@_split_path_b_tl {3}} + } + + \tl_set:Nx \l_@@_tmpa_tl { \tl_item:Nn \l_@@_split_path_b_tl {4} } + + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + + \int_zero:N \l_@@_tmpa_int + + \tl_case:Nn \l_@@_tmpa_tl + { + \c_spath_moveto_tl + { + \tl_clear:N \l_@@_split_path_a_tl + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + } + \c_spath_lineto_tl + { + \int_set:Nn \l_@@_tmpa_int {1} + } + \c_spath_curvetoa_tl + { + \int_set:Nn \l_@@_tmpa_int {3} + } + } + + \prg_replicate:nn { \l_@@_tmpa_int } + { + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + + \tl_put_right:Nx \l_@@_split_path_a_tl + { + \tl_item:Nn \l_@@_split_path_b_tl {1} + {\tl_item:Nn \l_@@_split_path_b_tl {2}} + {\tl_item:Nn \l_@@_split_path_b_tl {3}} + } + + \tl_set:Nx \l_@@_split_path_b_tl {\tl_tail:N \l_@@_split_path_b_tl} + } + + \tl_put_left:NV \l_@@_split_path_b_tl \c_spath_moveto_tl + + \tl_if_empty:NF \l_@@_split_path_a_tl + { + % Intersect the current segment with the rest of the path + \spath_intersect:NN \l_@@_split_path_a_tl \l_@@_split_path_b_tl + + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfintersectiongetsolutiontimes{##1}{\l_@@_split_first_tl}{\l_@@_split_second_tl} + \fp_compare:nT + { + \l_@@_split_first_tl < .99 + } + { + \tl_set:Nx \l_@@_tmpa_tl {\fp_to_decimal:n {\l_@@_split_first_tl + \l_@@_split_segment_int}} + \seq_put_right:NV \l_@@_split_first_seq \l_@@_tmpa_tl + } + } + } + + \spath_intersect:NN \l_@@_split_path_b_tl \l_@@_split_path_a_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfintersectiongetsolutiontimes{##1}{\l_@@_split_first_tl}{\l_@@_split_second_tl} + \fp_compare:nT + { + \l_@@_split_first_tl > .01 + } + { + \tl_set:Nx \l_@@_tmpa_tl {\fp_to_decimal:n {\l_@@_split_first_tl + \l_@@_split_segment_int + 1}} + \seq_put_right:NV \l_@@_split_first_seq \l_@@_tmpa_tl + } + } + } + + } + % Increment the segment counter + \int_incr:N \l_@@_split_segment_int + } + + % Sort the sequence by reverse order along the path + \seq_sort:Nn \l_@@_split_first_seq + { + \fp_compare:nNnTF { ##1 } < { ##2 } + { \sort_return_swapped: } + { \sort_return_same: } + } + + % Restore the original copy of the path + \tl_set_eq:NN \l_@@_split_path_b_tl \l_@@_split_path_b_final_tl + + % Clear the token lists + \tl_clear:N \l_@@_split_path_b_start_tl + \tl_clear:N \l_@@_split_path_b_end_tl + \tl_clear:N \l_@@_split_path_b_final_tl + + \tl_set:Nn \l_@@_split_prev_first_tl {-1} + + \seq_map_inline:Nn \l_@@_split_first_seq + { + \tl_set:Nn \l_@@_split_first_tl {##1} + \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_split_first_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l_@@_split_first_tl ) } + = + \fp_to_int:n {floor( \l_@@_split_prev_first_tl) } + } + { + \tl_set:Nx \l_@@_split_first_tl + { + \fp_eval:n { + floor( \l_@@_split_first_tl ) + + + ( \l_@@_split_first_tl - floor( \l_@@_split_first_tl) ) + / + ( \l_@@_split_prev_first_tl - floor( \l_@@_split_prev_first_tl) ) + } + } + } + \tl_set_eq:NN \l_@@_split_prev_first_tl \l_@@_tmpa_tl + + \spath_split_at:NNVV \l_@@_split_path_b_start_tl \l_@@_split_path_b_end_tl \l_@@_split_path_b_tl \l_@@_split_first_tl + + \tl_put_left:NV \l_@@_split_path_b_final_tl \l_@@_split_path_b_end_tl + \tl_set_eq:NN \l_@@_split_path_b_tl \l_@@_split_path_b_start_tl + + } + + \tl_put_left:NV \l_@@_split_path_b_final_tl \l_@@_split_path_b_tl + + \tl_if_empty:NT \l_@@_split_path_b_final_tl + { + \tl_set_eq:NN \l_@@_split_path_b_final_tl \l_@@_split_path_b_tl + } + + \spath_remove_empty_components:N \l_@@_split_path_b_final_tl + + \tl_gclear:N \g_@@_output_tl + \tl_gset_eq:NN \g_@@_output_tl \l_@@_split_path_b_final_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_at_self_intersections:Nn #1#2 +{ + \@@_split_at_self_intersections:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_split_at_self_intersections:Nn {NV} +\cs_new_protected_nopar:Npn \spath_split_at_self_intersections:N #1 +{ + \spath_split_at_self_intersections:NV #1#1 +} +\cs_generate_variant:Nn \spath_split_at_self_intersections:N {c} +\cs_new_protected_nopar:Npn \spath_gsplit_at_self_intersections:Nn #1#2 +{ + \@@_split_at_self_intersections:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at_self_intersections:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gsplit_at_self_intersections:N #1 +{ + \spath_gsplit_at_self_intersections:NV #1#1 +} +\cs_generate_variant:Nn \spath_gsplit_at_self_intersections:N {c} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{ +% \spath_join_component:Nnn, +% \spath_join_component:Nn, +% \spath_gjoin_component:Nnn, +% \spath_gjoin_component:Nn, +% } +% Join the specified component of the spath to its predecessor. +% \begin{macrocode} +\tl_new:N \l_@@_tmpj_tl +\cs_new_protected_nopar:Npn \@@_join_component:nn #1#2 +{ + \group_begin: + \spath_components_to_seq:Nn \l_@@_tmpa_seq {#1} + \int_compare:nT + { + #2 == 1 + } + { + \tl_clear:N \l_@@_tmpj_tl + \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpj_tl + + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpj_tl {\tl_tail:N \l_@@_tmpj_tl} + } + + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpj_tl + } + \bool_if:nT + { + \int_compare_p:n + { + #2 > 1 + } + && + \int_compare_p:n + { + #2 <= \seq_count:N \l_@@_tmpa_seq + } + } + { + + \seq_clear:N \l_@@_tmpb_seq + \seq_map_indexed_inline:Nn \l_@@_tmpa_seq + { + \tl_set:Nn \l_@@_tmpj_tl {##2} + \int_compare:nT {##1 = #2} + { + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpj_tl {\tl_tail:N \l_@@_tmpj_tl} + } + } + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpj_tl + } + + \seq_set_eq:NN \l_@@_tmpa_seq \l_@@_tmpb_seq + } + + \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpa_seq {} } + \group_end: +} +\cs_new_protected_nopar:Npn \spath_join_component:Nnn #1#2#3 +{ + \@@_join_component:nn {#2}{#3} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_join_component:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_join_component:Nn #1#2 +{ + \spath_join_component:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_join_component:Nn {cn, NV, cV} +\cs_new_protected_nopar:Npn \spath_gjoin_component:Nnn #1#2#3 +{ + \@@_join_component:nn {#2}{#3} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_gjoin_component:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_gjoin_component:Nn #1#2 +{ + \spath_gjoin_component:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gjoin_component:Nn {cn, NV, cV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_spot_weld_components:Nn, +% \spath_spot_weld_components:N, +% \spath_spot_gweld_components:Nn, +% \spath_spot_gweld_components:N, +% } +% Weld together any components where the last point of one is at the start point of the next (within a tolerance). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_spot_weld_components:n #1 +{ + \group_begin: + \dim_zero:N \l_@@_move_x_dim + \dim_zero:N \l_@@_move_y_dim + + \spath_components_to_seq:Nn \l_@@_tmpa_seq {#1} + \seq_clear:N \l_@@_tmpb_seq + \dim_set:Nn \l_@@_move_x_dim {\tl_item:nn {#1} {2} + 10 pt} + \dim_set:Nn \l_@@_move_y_dim {\tl_item:nn {#1} {3} + 10 pt} + + \int_set:Nn \l_@@_tmpa_int {\seq_count:N \l_@@_tmpa_seq} + + \seq_map_inline:Nn \l_@@_tmpa_seq + { + \tl_set:Nn \l_@@_tmpa_tl {##1} + \bool_if:nT + { + \dim_compare_p:n + { + \dim_abs:n {\l_@@_move_x_dim - \tl_item:Nn \l_@@_tmpa_tl {2} } < 0.01pt + } + && + \dim_compare_p:n + { + \dim_abs:n {\l_@@_move_y_dim - \tl_item:Nn \l_@@_tmpa_tl {3} } < 0.01pt + } + } + { + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \int_decr:N \l_@@_tmpa_int + } + \tl_reverse:N \l_@@_tmpa_tl + \dim_set:Nn \l_@@_move_x_dim {\tl_item:Nn \l_@@_tmpa_tl {2}} + \dim_set:Nn \l_@@_move_y_dim {\tl_item:Nn \l_@@_tmpa_tl {1}} + \tl_reverse:N \l_@@_tmpa_tl + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl + } + + \tl_set:Nx \l_@@_tmpa_tl {\seq_use:Nn \l_@@_tmpb_seq {} } + \spath_components_to_seq:NV \l_@@_tmpb_seq \l_@@_tmpa_tl + + + \spath_initialpoint:Nn \l_@@_tmpa_tl {#1} + \spath_finalpoint:Nn \l_@@_tmpb_tl {#1} + + \bool_if:nT + { + \dim_compare_p:n + { + \dim_abs:n {\tl_item:Nn \l_@@_tmpa_tl {1} - \tl_item:Nn \l_@@_tmpb_tl {1} } < 0.01pt + } + && + \dim_compare_p:n + { + \dim_abs:n {\tl_item:Nn \l_@@_tmpa_tl {2} - \tl_item:Nn \l_@@_tmpb_tl {2} } < 0.01pt + } + } + { + \int_compare:nTF + { + \seq_count:N \l_@@_tmpb_seq > 1 + } + { + \seq_pop_left:NN \l_@@_tmpb_seq \l_@@_tmpb_tl + + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl} + } + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpb_tl + } + { + \tl_set:NV \l_@@_tmpb_tl \c_spath_closepath_tl + \tl_put_right:Nx \l_@@_tmpb_tl + { + { \tl_item:Nn \l_@@_tmpa_tl {1} } + { \tl_item:Nn \l_@@_tmpa_tl {2} } + } + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpb_tl + } + } + + \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpb_seq {}} + \group_end: +} +\cs_new_protected_nopar:Npn \spath_spot_weld_components:Nn #1#2 +{ + \@@_spot_weld_components:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_spot_weld_components:Nn {NV, cV, cn} +\cs_new_protected_nopar:Npn \spath_spot_weld_components:N #1 +{ + \spath_spot_weld_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_spot_weld_components:N {c} +\cs_new_protected_nopar:Npn \spath_spot_gweld_components:Nn #1#2 +{ + \@@_spot_weld_components:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_generate_variant:Nn \spath_spot_gweld_components:Nn {NV, cV, cn} +\cs_new_protected_nopar:Npn \spath_spot_gweld_components:N #1 +{ + \spath_spot_gweld_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_spot_gweld_components:N {c} +% \end{macrocode} +% \end{macro} +% +% \subsection{Exporting Commands} +% +% \begin{macro}{ +% \spath_convert_to_svg:Nn, +% \spath_gconvert_to_svg:Nn, +% } +% Convert the soft path to an SVG document. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_convert_to_svg:n #1 +{ + \group_begin: + \tl_clear:N \l_@@_tmpa_tl + \tl_put_right:Nn \l_@@_tmpa_tl + { + <?xml~ version="1.0"~ standalone="no"?> + \iow_newline: + <!DOCTYPE~ svg~ PUBLIC~ "-//W3C//DTD SVG 1.1//EN"~ + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> + \iow_newline: + <svg~ xmlns="http://www.w3.org/2000/svg"~ version="1.1"~viewBox=" + } + + \spath_minbb:Nn \l_@@_tmpb_tl {#1} + \spath_maxbb:Nn \l_@@_tmpc_tl {#1} + \tl_put_right:Nx \l_@@_tmpa_tl + { + \dim_to_decimal:n + { + \tl_item:Nn \l_@@_tmpb_tl {1} - 10pt + } + \exp_not:n {~} + \dim_to_decimal:n + { + \tl_item:Nn \l_@@_tmpb_tl {2} - 10pt + } + \exp_not:n {~} + \dim_to_decimal:n + { + \tl_item:Nn \l_@@_tmpc_tl {1} + - + \tl_item:Nn \l_@@_tmpb_tl {1} + + 20pt + } + \exp_not:n {~} + \dim_to_decimal:n + { + \tl_item:Nn \l_@@_tmpc_tl {2} + - + \tl_item:Nn \l_@@_tmpb_tl {2} + + 20pt + } + } + + \tl_put_right:Nn \l_@@_tmpa_tl + { + "> + \iow_newline: + <path~ d=" + } + \tl_set:Nn \l_@@_tmpc_tl {use:n} + \tl_map_inline:Nn #1 + { + \tl_set:Nn \l_@@_tmpb_tl {##1} + \tl_case:NnF \l_@@_tmpb_tl + { + \c_spath_moveto_tl + { + \tl_put_right:Nn \l_@@_tmpa_tl {M~} + \tl_set:Nn \l_@@_tmpc_tl {use:n} + } + \c_spath_lineto_tl + { + \tl_put_right:Nn \l_@@_tmpa_tl {L~} + \tl_set:Nn \l_@@_tmpc_tl {use:n} + } + \c_spath_closepath_tl + { + \tl_put_right:Nn \l_@@_tmpa_tl {Z~} + \tl_set:Nn \l_@@_tmpc_tl {use_none:n} + } + \c_spath_curvetoa_tl + { + \tl_put_right:Nn \l_@@_tmpa_tl {C~} + \tl_set:Nn \l_@@_tmpc_tl {use:n} + } + \c_spath_curvetob_tl { + \tl_set:Nn \l_@@_tmpc_tl {use:n} + } + \c_spath_curveto_tl { + \tl_set:Nn \l_@@_tmpc_tl {use:n} + } + } + { + \tl_put_right:Nx \l_@@_tmpa_tl {\use:c { \l_@@_tmpc_tl } {\dim_to_decimal:n {##1}} ~} + } + } + \tl_put_right:Nn \l_@@_tmpa_tl + { + "~ fill="none"~ stroke="black"~ /> + \iow_newline: + </svg> + \iow_newline: + } + \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_convert_to_svg:Nn #1#2 +{ + \@@_convert_to_svg:n {#2} + \tl_set_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +\cs_new_protected_nopar:Npn \spath_gconvert_to_svg:Nn #1#2 +{ + \@@_convert_to_svg:n {#2} + \tl_gset_eq:NN #1 \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_export_to_svg:nn +% } +% Save a soft path to an SVG file. +% \begin{macrocode} +\iow_new:N \g_@@_stream +\cs_new_protected_nopar:Npn \spath_export_to_svg:nn #1#2 +{ + \spath_convert_path_to_svg:Nn \l_@@_iterp_tl {#2} + \iow_open:Nn \g_@@_stream {#1 .svg} + \iow_now:Nx \g_@@_stream + { + \tl_use:N \l_@@_iterp_tl + } + \iow_close:N \g_@@_stream +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\spath_show:n} +% Displays the soft path on the terminal. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_show:n #1 +{ + \int_step_inline:nnnn {1} {3} {\tl_count:n {#1}} + { + \iow_term:x { + \tl_item:Nn \l_@@_tmpa_tl {##1} + {\tl_item:Nn \l_@@_tmpa_tl {##1+1}} + {\tl_item:Nn \l_@@_tmpa_tl {##1+2}} + } + } +} +\cs_generate_variant:Nn \spath_show:n {V, v} +% \end{macrocode} +% \end{macro} + +% \subsubsection{PGF and TikZ Interface Functions} +% +% Spaths come from PGF so we need some functions that get and set spaths from the pgf system. +% +% \begin{macro}{ +% \spath_get_current_path:N, +% \spath_gget_current_path:N +% } +% Grab the current soft path from PGF. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_get_current_path:N #1 +{ + \pgfsyssoftpath@getcurrentpath #1 +} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_gget_current_path:N #1 +{ + \pgfsyssoftpath@getcurrentpath #1 + \tl_gset_eq:NN #1 #1 +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\spath_protocol_path:n} +% This feeds the bounding box of the soft path to PGF to ensure that its current bounding box contains the soft path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_protocol_path:n #1 +{ + \spath_minbb:Nn \l_@@_tmpa_tl {#1} + \exp_last_unbraced:NV \pgf@protocolsizes\l_@@_tmpa_tl + + \spath_maxbb:Nn \l_@@_tmpa_tl {#1} + \exp_last_unbraced:NV \pgf@protocolsizes\l_@@_tmpa_tl +} +\cs_generate_variant:Nn \spath_protocol_path:n {V} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_set_current_path:n, +% \spath_set_current_path:N +% } +% Sets the current path to the specified soft path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_set_current_path:n #1 +{ + \spath_protocol_path:n {#1} + \tl_set:Nn \l_@@_tmpa_tl {#1} + \pgfsyssoftpath@setcurrentpath\l_@@_tmpa_tl +} +\cs_new_protected_nopar:Npn \spath_set_current_path:N #1 +{ + \spath_protocol_path:V #1 + \pgfsyssoftpath@setcurrentpath #1 +} +\cs_generate_variant:Nn \spath_set_current_path:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{ +% \spath_use_path:nn +% } +% Uses the given soft path at the PGF level. +% \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_tikz_path:nn} +% Uses the given soft path at the TikZ level. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2 +{ + \path[#1] \pgfextra{ + \spath_set_current_path:n {#2} + \tl_put_right:Nn \tikz@preactions {\def\tikz@actions@path{#2}} + }; +} +\cs_generate_variant:Nn \spath_tikz_path:nn {Vn, VV, nv, Vv, nV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\spath_set_tikz_coords:n} +% Sets the \Verb+\tikz@lastx+ and other coordinates from the soft path. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \spath_set_tikz_coords:n #1 +{ + \spath_finalpoint:Nn \l_@@_tmpa_tl {#1} + \tl_set:Nx \l_@@_tmpa_tl + { + \exp_not:c {tikz@lastx}=\tl_item:Nn \l_@@_tmpa_tl {1} + \exp_not:c {tikz@lasty}=\tl_item:Nn \l_@@_tmpa_tl {2} + \exp_not:c {tikz@lastxsaved}=\tl_item:Nn \l_@@_tmpa_tl {1} + \exp_not:c {tikz@lastysaved}=\tl_item:Nn \l_@@_tmpa_tl {2} + } + \tl_use:N \l_@@_tmpa_tl +} +\cs_generate_variant:Nn \spath_set_tikz_coords:n {V, v} +% \end{macrocode} +% \end{macro} +% +% \iffalse +%</spath3> +% \fi +% +% \section{The TikZ interface} +% +% \iffalse +%<*tikzspath3> +% \fi +% +% This provides an interface to the soft path manipulation routines via a series of TikZ keys. +% They all live in the \texttt{spath} family. +% +% +% \begin{macrocode} +\RequirePackage{spath3} +\RequirePackage{expl3} +\ExplSyntaxOn + +\tl_new:N \l_@@_current_tl +\tl_new:N \l_@@_reverse_tl +\tl_new:N \l_@@_prefix_tl +\tl_new:N \l_@@_suffix_tl +\tl_new:N \g_@@_smuggle_tl +\seq_new:N \g_@@_tmpa_seq +\seq_new:N \g_@@_tmpb_seq +\bool_new:N \l_@@_draft_bool +% \end{macrocode} +% +% When saving a soft path, by default we use a naming convention that is compatible with the intersections library so that paths saved here and paths saved by the \texttt{name path} facility of the intersections library are mutually exchangeable. +% +% \begin{macrocode} +\tl_set:Nn \l_@@_prefix_tl {tikz@intersect@path@name@} +\tl_set:Nn \l_@@_suffix_tl {} +% \end{macrocode} +% +% When a soft path is grabbed from TikZ we're usually deep in a group so I've adapted the code from the intersections library to dig the definition out of the group without making everything global. +% +% \begin{macrocode} +\tl_new:N \g_@@_tikzfinish_tl +\cs_new_protected_nopar:Npn \spath_at_end_of_path: +{ + \tl_use:N \g_@@_tikzfinish_tl + \tl_gclear:N \g_@@_tikzfinish_tl +} +\tl_put_right:Nn \tikz@finish {\spath_at_end_of_path:} + +\cs_new_protected_nopar:Npn \spath_save_path:Nn #1#2 +{ + \tl_gput_right:Nn \g_@@_tikzfinish_tl + { + \tl_clear_new:N #1 + \tl_set:Nn #1 {#2} + } +} +\cs_generate_variant:Nn \spath_save_path:Nn {cn, NV, cV} + +\cs_new_protected_nopar:Npn \spath_gsave_path:Nn #1#2 +{ + \tl_gput_right:Nn \g_@@_tikzfinish_tl + { + \tl_gclear_new:N #1 + \tl_gset:Nn #1 {#2} + } +} +\cs_generate_variant:Nn \spath_gsave_path:Nn {cn, NV, cV} +% \end{macrocode} +% +% Now we define all of our keys. +% +% \begin{macrocode} +\tikzset{ +% \end{macrocode} +% +% We're in the \texttt{spath} key family. +% +% \begin{macrocode} + spath/.is~family, + spath/.cd, +% \end{macrocode} +% +% We provide for saving soft paths with a specific prefix and suffix in the name. +% The default is to make it compatible with the intersections library. +% +% \begin{macrocode} + set~ prefix/.store~ in=\l_@@_prefix_tl, + prefix/.is~choice, + prefix/default/.style={ + /tikz/spath/set~ prefix=tikz@intersect@path@name@ + }, + set~ suffix/.store~ in=\l_@@_suffix_tl, + suffix/.is~choice, + suffix/default/.style={ + /tikz/spath/set~ suffix={} + }, + set~ name/.style={ + /tikz/spath/prefix=#1, + /tikz/spath/suffix=#1 + }, +% \end{macrocode} +% +% Keys for saving and cloning a soft path. +% +% \begin{macrocode} + save/.code={ + \tikz@addmode{ + \spath_get_current_path:N \l_@@_tmpa_tl + \spath_bake_round:NV \l_@@_tmpa_tl \l_@@_tmpa_tl + \spath_save_path:cV {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} \l_@@_tmpa_tl + } + }, + clone/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + { + \tl_clear_new:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \tl_set_eq:cc + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + } + }, + clone~ global/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + { + \tl_gclear_new:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \tl_gset_eq:cc + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + } + }, + save~ global/.code={ + \tikz@addmode{ + \spath_get_current_path:N \l_@@_tmpa_tl + \spath_bake_round:NV \l_@@_tmpa_tl \l_@@_tmpa_tl + \spath_gsave_path:cV + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \l_@@_tmpa_tl + } + }, +% \end{macrocode} +% +% Saves a soft path to the aux file. +% +% \begin{macrocode} + save~ to~ aux/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_save_to_aux:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Restores a soft path to the current path. +% +% \begin{macrocode} + restore/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_set_current_path:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \spath_set_tikz_coords:v + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Diagnostic, show the current path in the terminal and log. +% +% \begin{macrocode} + show~current~path/.code={ + \tikz@addmode{ + \pgfsyssoftpath@getcurrentpath\l_@@_tmpa_tl + \iow_term:n {---~ current~ soft~ path~ ---} + \spath_show:V \l_@@_tmpa_tl + } + }, +% \end{macrocode} +% +% Diagnostic, show the named soft path in the terminal and log. +% +% \begin{macrocode} + show/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \iow_term:n {---~ soft~ path~ #1~ ---} + \spath_show:v {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Appends the named path to the current path with a weld. +% +% \begin{macrocode} + append/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_get_current_path:N \l_@@_current_tl + \spath_weld:Nv + \l_@@_current_tl + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \spath_set_current_path:N \l_@@_current_tl + \spath_set_tikz_coords:V \l_@@_current_tl + } + }, +% \end{macrocode} +% +% Joins the second named path to the first. +% +% \begin{macrocode} + join~ with/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + { + \spath_append:cv + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + } + } + }, +% \end{macrocode} +% +% Does a ``spot weld'' on a soft path, which means that any components that start where the previous component ends are welded together. +% +% \begin{macrocode} + spot~ weld/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_spot_weld_components:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Reverses the named path. +% +% \begin{macrocode} + reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_reverse:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Appends the reversal of the path to the current path. +% +% \begin{macrocode} + append~ reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_reverse:Nv + \l_@@_reverse_tl + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \spath_get_current_path:N \l_@@_current_tl + \spath_weld:NV \l_@@_current_tl \l_@@_reverse_tl + \spath_set_current_path:N \l_@@_current_tl + \spath_set_tikz_coords:V \l_@@_current_tl + } + }, +% \end{macrocode} +% +% Inserts the named path into the current path as-is, meaning without transforming or welding it. +% +% \begin{macrocode} + insert/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_get_current_path:N \l_@@_current_tl + \spath_append:Nv + \l_@@_current_tl + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \spath_set_current_path:N \l_@@_current_tl + \spath_set_tikz_coords:V \l_@@_current_tl + } + }, +% \end{macrocode} +% +% Inserts the reverse of the named path. +% +% \begin{macrocode} + insert~ reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_reverse:Nv + \l_@@_reverse_tl + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \spath_get_current_path:N \l_@@_current_tl + \spath_append:NV \l_@@_current_tl \l_@@_reverse_tl + \spath_set_current_path:N \l_@@_current_tl + \spath_set_tikz_coords:V \l_@@_current_tl + } + }, +% \end{macrocode} +% +% These keys shorten the path. +% +% \begin{macrocode} + shorten~ at~ end/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_shorten_at_end:cn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2} + } + }, + shorten~ at~ start/.code~ 2~ args ={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_shorten_at_start:cn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2} + } + }, + shorten~ at~ both~ ends/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_shorten_at_end:cn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2} + \spath_shorten_at_start:cn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2} + } + }, +% \end{macrocode} +% +% This translates the named path. +% +% \begin{macrocode} + translate/.code~ n~ args={3}{ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_translate:cnn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{#2}{#3} + } + }, +% \end{macrocode} +% +% Exports the path as an SVG file. +% +% \begin{macrocode} + export~ to~ svg/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_export_to_svg:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Transforms the named path using TikZ transformation specifications. +% +% \begin{macrocode} + transform/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \group_begin: + \pgftransformreset + \tikzset{#2} + \pgfgettransform \l_@@_tmpa_tl + \tl_gset:Nn \g_@@_smuggle_tl + { + \spath_transform:cnnnnnn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl + \group_end: + \tl_use:N \g_@@_smuggle_tl + } + }, + transform~global/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \group_begin: + \pgftransformreset + \tikzset{#2} + \pgfgettransform \l_@@_tmpa_tl + \tl_gset:Nn \g_@@_smuggle_tl + { + \spath_gtransform:cnnnnnn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl + \group_end: + \tl_use:N \g_@@_smuggle_tl + } + }, +% \end{macrocode} +% +% Splits two paths at their mutual intersections. +% +% \begin{macrocode} + split~ at~ intersections/.code~ n~ args={2}{ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + { + \spath_split_at_intersections:cc + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl} + } + } + }, +% \end{macrocode} +% +% Splits a path at its self-intersections. +% +% \begin{macrocode} + split~ at~ self~ intersections/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_split_at_self_intersections:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% Extract the components of a path into a comma separated list (suitable for using in a \Verb+\foreach+ loop). +% +% \begin{macrocode} + get~ components~ of/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \clist_clear_new:N #2 + \spath_components_to_seq:Nv + \l_@@_tmpa_seq + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \seq_map_inline:Nn \l_@@_tmpa_seq + { + \tl_new:c + {\tl_use:N \l_@@_prefix_tl anonymous_\int_use:N \g_@@_anon_int \tl_use:N \l_@@_suffix_tl} + \tl_set:cn + {\tl_use:N \l_@@_prefix_tl anonymous_\int_use:N \g_@@_anon_int \tl_use:N \l_@@_suffix_tl} {##1} + \clist_put_right:Nx #2 {anonymous_\int_use:N \g_@@_anon_int} + \int_gincr:N \g_@@_anon_int + } + } + }, +% \end{macrocode} +% +% Loop through the components of a soft path and render each as a separate TikZ path so that they can be individually styled. +% +% \begin{macrocode} + render~ components/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \group_begin: + \spath_components_to_seq:Nv + \l_@@_tmpa_seq + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \seq_map_indexed_inline:Nn \l_@@_tmpa_seq + { + \spath_tikz_path:nn + { + every~ spath~ component/.try, + spath ~component~ ##1/.try, + spath ~component/.try={##1}, + every~ #1~ component/.try, + #1 ~component~ ##1/.try, + #1 ~component/.try={##1}, + } + { + ##2 + } + } + \group_end: + } + }, +% \end{macrocode} +% +% This puts gaps between components of a soft path. +% The list of components is passed through a \Verb+\foreach+ loop so can use the shortcut syntax from those loops. +% +% \begin{macrocode} + insert~ gaps~ after~ components/.code~ n~ args={3}{ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \group_begin: + \seq_gclear:N \g_@@_tmpa_seq + \seq_gclear:N \g_@@_tmpb_seq + \foreach \l_@@_tmpa_tl in {#3} + { + \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl + \seq_gput_right:Nx \g_@@_tmpb_seq {\int_eval:n { \l_@@_tmpa_tl + 1 }} + } + \spath_components_to_seq:Nv + \l_@@_tmpa_seq + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \seq_clear:N \l_@@_tmpb_seq + \seq_map_indexed_inline:Nn \l_@@_tmpa_seq + { + \tl_set:Nn \l_@@_tmpa_tl {##2} + \seq_if_in:NnT \g_@@_tmpa_seq {##1} + { + \spath_shorten_at_end:Nn \l_@@_tmpa_tl {#2/2} + } + \seq_if_in:NnT \g_@@_tmpb_seq {##1} + { + \spath_shorten_at_start:Nn \l_@@_tmpa_tl {#2/2} + } + \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl + } + \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpb_seq {} } + \group_end: + \tl_set_eq:cN + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + \g_@@_output_tl + \tl_gclear:N \g_@@_output_tl + } + }, +% \end{macrocode} +% +% Join the specified components together, joining each to its previous one. +% +% \begin{macrocode} + join~ components/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \seq_gclear:N \g_@@_tmpa_seq + \foreach \l_@@_tmpa_tl in {#2} + { + \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl + } + \seq_gsort:Nn \g_@@_tmpa_seq + { + \int_compare:nNnTF {##1} > {##2} + { \sort_return_same: } + { \sort_return_swapped: } + } + \seq_map_inline:Nn \g_@@_tmpa_seq + { + \spath_join_component:cn + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{##1} + } + } + }, +% \end{macrocode} +% +% Remove all components of the path that don't actually draw anything. +% +% \begin{macrocode} + remove~ empty~ components/.code={ + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_remove_empty_components:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + }, +% \end{macrocode} +% +% This puts a conditional around the \texttt{spot weld} key because when figuring out a knot drawing then we will initially want to render it without the spot weld to keep the number of components constant. +% +% \begin{macrocode} + draft~ mode/.is~ choice, + draft~ mode/true/.code={ + \bool_set_true:N \l_@@_draft_bool + }, + draft~ mode/false/.code={ + \bool_set_false:N \l_@@_draft_bool + }, + maybe~ spot~ weld/.code={ + \bool_if:NF \l_@@_draft_bool + { + \tl_if_exist:cT {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + { + \spath_spot_weld_components:c + {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} + } + } + }, +% \end{macrocode} +% +% Set the transformation to lie along a path. +% +% \begin{macrocode} + transform~ to/.code~ 2~ args={ + \group_begin: + \tl_if_exist:cTF + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + { + \spath_reallength:Nv + \l_@@_tmpa_int + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + + \tl_set:Nx \l_@@_tmpb_tl + {\fp_to_decimal:n {(#2) * (\l_@@_tmpa_int)}} + \spath_transformation_at:NvV \l_@@_tmpc_tl + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + \l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpc_tl + } + { + \tl_gset_eq:NN \g_@@_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} } + } + \group_end: + \exp_last_unbraced:NV \pgfsettransformentries \g_@@_smuggle_tl + \tl_gclear:N \g_@@_smuggle_tl + }, +% \end{macrocode} +% +% As above, but with a possible extra \(180^\circ\) rotation if needed to ensure that the new \(y\)--axis points vaguely upwards. +% +% \begin{macrocode} + upright~ transform~ to/.code~ 2~ args={ + \group_begin: + \tl_if_exist:cTF + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + { + \spath_reallength:Nv + \l_@@_tmpa_int + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + + \tl_set:Nx \l_@@_tmpb_tl + {\fp_to_decimal:n {(#2) * (\l_@@_tmpa_int)}} + \spath_transformation_at:NvV \l_@@_tmpc_tl + { + \tl_use:N \l_@@_prefix_tl + #1 + \tl_use:N \l_@@_suffix_tl + } + \l_@@_tmpb_tl + \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpc_tl + } + { + \tl_gset_eq:NN \g_@@_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} } + } + \fp_compare:nT { \tl_item:Nn \g_@@_smuggle_tl {4} < 0} + { + \tl_gset:Nx \g_@@_smuggle_tl + { + { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {1})} } + { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {2})} } + { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {3})} } + { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {4})} } + { \tl_item:Nn \g_@@_smuggle_tl {5} } + { \tl_item:Nn \g_@@_smuggle_tl {6} } + } + } + \group_end: + \exp_last_unbraced:NV \pgfsettransformentries \g_@@_smuggle_tl + \tl_gclear:N \g_@@_smuggle_tl + }, +% \end{macrocode} +% +% This is a useful set of styles for drawing a knot diagram. +% +% \begin{macrocode} + knot/.style~ n~ args={3}{ + spath/.cd, + split~ at~ self~ intersections=#1, + insert~ gaps~ after~ components={#1}{#2}{#3}, + maybe~ spot~ weld=#1, + render~ components=#1 + }, +} +% \end{macrocode} +% +% This defines a coordinate system that finds a position on a soft path. +% +% \begin{macrocode} +\tikzdeclarecoordinatesystem{spath}{% + \group_begin: + \tl_set:Nn \l_@@_tmpa_tl {#1} + \tl_trim_spaces:N \l_@@_tmpa_tl + + \seq_set_split:NnV \l_@@_tmpa_seq {~} \l_@@_tmpa_tl + \seq_pop_right:NN \l_@@_tmpa_seq \l_@@_tmpb_tl + + \tl_set:Nx \l_@@_tmpa_tl { \seq_use:Nn \l_@@_tmpa_seq {~} } + \tl_if_exist:cTF + { + \tl_use:N \l_@@_prefix_tl + \tl_use:N \l_@@_tmpa_tl + \tl_use:N \l_@@_suffix_tl + } + { + + \tl_set_eq:Nc + \l_@@_tmpa_tl + { + \tl_use:N \l_@@_prefix_tl + \tl_use:N \l_@@_tmpa_tl + \tl_use:N \l_@@_suffix_tl + } + + \tl_if_empty:NTF \l_@@_tmpa_tl + { + \tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin + } + { + \spath_reallength:NV \l_@@_tmpa_int \l_@@_tmpa_tl + \tl_set:Nx \l_@@_tmpb_tl + {\fp_to_decimal:n {(\l_@@_tmpb_tl) * (\l_@@_tmpa_int)}} + \spath_point_at:NVV \l_@@_tmpc_tl \l_@@_tmpa_tl \l_@@_tmpb_tl + + \tl_clear:N \l_@@_tmpd_tl + \tl_put_right:Nn \l_@@_tmpd_tl {\pgf@x=} + \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {1}} + \tl_put_right:Nn \l_@@_tmpd_tl {\relax} + \tl_put_right:Nn \l_@@_tmpd_tl {\pgf@y=} + \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {2}} + \tl_put_right:Nn \l_@@_tmpd_tl {\relax} + \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpd_tl + } + } + { + \tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin + } + \group_end: + \tl_use:N \g_@@_smuggle_tl +} + +\ExplSyntaxOff +% \end{macrocode} +% \iffalse +%</tikzspath3> +% \fi +% +% \iffalse +%<*calligraphy> +% \fi +% +% \section{The Calligraphy Package} +% +% \begin{macrocode} +%<@@=cal> +% \end{macrocode} +% +% \subsection{Initialisation} +% \begin{macrocode} +\RequirePackage{spath3} +\ExplSyntaxOn + +\tl_new:N \l_@@_tmpa_tl +\tl_new:N \l_@@_tmpb_tl +\tl_new:N \l_@@_tmp_path_tl +\tl_new:N \l_@@_tmp_rpath_tl +\tl_new:N \l_@@_tmp_rpathb_tl +\tl_new:N \l_@@_tmp_patha_tl + +\seq_new:N \l_@@_tmpa_seq + +\int_new:N \l_@@_tmpa_int +\int_new:N \l_@@_tmpb_int +\int_new:N \g_@@_path_component_int +\int_new:N \g_@@_label_int + +\fp_new:N \l_@@_tmpa_fp +\fp_new:N \l_@@_tmpb_fp +\fp_new:N \l_@@_tmpc_fp +\fp_new:N \l_@@_tmpd_fp +\fp_new:N \l_@@_tmpe_fp + +\dim_new:N \l_@@_tmpa_dim +\dim_new:N \l_@@_tmpb_dim +\dim_new:N \l_@@_tmpc_dim +\dim_new:N \l_@@_tmpd_dim +\dim_new:N \l_@@_tmpe_dim +\dim_new:N \l_@@_tmpf_dim +\dim_new:N \l_@@_tmpg_dim +\dim_new:N \l_@@_tmph_dim + +\bool_new:N \l_@@_annotate_bool +\bool_new:N \l_@@_taper_start_bool +\bool_new:N \l_@@_taper_end_bool +\bool_new:N \l_@@_taperable_bool + +\dim_new:N \l_@@_taper_width_dim +\dim_new:N \l_@@_line_width_dim + +\bool_set_true:N \l_@@_taper_start_bool +\bool_set_true:N \l_@@_taper_end_bool + +\cs_generate_variant:Nn \tl_put_right:Nn {Nv} + +\msg_new:nnn { calligraphy } { undefined pen } { The~ pen~ "#1"~ is~ not~ defined. } +% \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_@@_tmpa_tl + \spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpa_tl + \seq_gclear_new:c {g_@@_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + \seq_gset_eq:cN {g_@@_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} \l_@@_tmpa_seq + \pgfusepath{discard}% + } + }, + define~pen/.default={default}, + use~pen/.code={ + \tikzset{pen~name=#1} + \int_gzero:N \g_@@_path_component_int + \cs_set_eq:NN \pgfpathmoveto \cal_moveto:n + \tikz@addmode{ + \pgfsyssoftpath@getcurrentpath\l_@@_tmpa_tl + \spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpa_tl + \tl_if_exist:cTF {g_@@_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + { + \cal_path_create:Nc \l_@@_tmpa_seq {g_@@_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + } + { + \msg_warning:nnx { calligraphy } { undefined pen } { \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_@@_taper_start_bool + } + { + \bool_set_false:N \l_@@_taper_start_bool + } + }, + taper~start/.default={true}, + taper~end/.code={ + \tl_if_eq:nnTF {#1} {true} + { + \bool_set_true:N \l_@@_taper_end_bool + } + { + \bool_set_false:N \l_@@_taper_end_bool + } + }, + taper~end/.default={true}, + taper~width/.code={\dim_set:Nn \l_@@_taper_width_dim {#1}}, + nib~style/.code~2~args={ + \tl_clear_new:c {l_@@_nib_style_#1} + \tl_set:cn {l_@@_nib_style_#1} {#2} + }, + stroke~style/.code~2~args={ + \tl_clear_new:c {l_@@_stroke_style_#1} + \tl_set:cn {l_@@_stroke_style_#1} {#2} + }, + this~stroke~style/.code={ + \tl_clear_new:c {l_@@_stroke_inline_style_ \int_use:N \g_@@_path_component_int} + \tl_set:cn {l_@@_stroke_inline_style_ \int_use:N \g_@@_path_component_int} {#1} + }, + annotate/.style={ + annotate~if, + annotate~reset, + annotation~style/.update~value={#1}, + }, + annotate~if/.default={true}, + annotate~if/.code={ + \tl_if_eq:nnTF {#1} {true} + { + \bool_set_true:N \l_@@_annotate_bool + } + { + \bool_set_false:N \l_@@_annotate_bool + } + }, + annotate~reset/.code={ + \int_gzero:N \g_@@_label_int + }, + annotation~style/.initial={draw,->}, + annotation~shift/.initial={(0,1ex)}, + every~annotation~node/.initial={anchor=south~west}, + annotation~node~style/.code~2~args={ + \tl_clear_new:c {l_@@_annotation_style_ #1 _tl} + \tl_set:cn {l_@@_annotation_style_ #1 _tl}{#2} + }, + tl~use:N/.code={ + \exp_args:NV \pgfkeysalso #1 + }, + tl~use:c/.code={ + \tl_if_exist:cT {#1} + { + \exp_args:Nv \pgfkeysalso {#1} + } + }, + /handlers/.update~style/.code={ + \tl_if_eq:nnF {#1} {\pgfkeysnovalue} + { + \pgfkeys{\pgfkeyscurrentpath/.code=\pgfkeysalso{#1}} + } + }, + /handlers/.update~value/.code={ + \tl_if_eq:nnF {#1} {\pgfkeysnovalue} + { + \pgfkeyssetvalue{\pgfkeyscurrentpath}{#1} + } + }, +} +% \end{macrocode} +% +% Some wrappers around the TikZ keys. +% \begin{macrocode} +\NewDocumentCommand \pen { O{} } +{ + \path[define~ pen,every~ calligraphy~ pen/.try,#1] +} + +\NewDocumentCommand \definepen { O{} } +{ + \tikz \path[define~ pen,every~ calligraphy~ pen/.try,#1] +} + +\NewDocumentCommand \calligraphy { O{} } +{ + \path[use~ pen,every~ calligraphy/.try,#1] +} +% \end{macrocode} +% +% \subsection{The Path Creation} +% +% \begin{macro}[internal]{\cal_path_create:NN} +% This is the main command for creating the calligraphic paths. +% First argument is the given path +% Second argument is the pen path +% \begin{macrocode} +\cs_new_protected_nopar:Npn \cal_path_create:NN #1#2 +{ + \int_zero:N \l_@@_tmpa_int + \seq_map_inline:Nn #1 + { + \int_compare:nT {\tl_count:n {##1} > 3} + { + + \int_incr:N \l_@@_tmpa_int + \int_zero:N \l_@@_tmpb_int + + \tl_set:Nn \l_@@_tmp_path_tl {##1} + \spath_open:N \l_@@_tmp_path_tl + \spath_reverse:NV \l_@@_tmp_rpath_tl \l_@@_tmp_path_tl + + \seq_map_inline:Nn #2 + { + \int_incr:N \l_@@_tmpb_int + \group_begin: + \pgfsys@beginscope + \cal_apply_style:c {l_@@_stroke_style_ \int_use:N \l_@@_tmpa_int} + \cal_apply_style:c {l_@@_stroke_inline_style_ \int_use:N \l_@@_tmpa_int} + \cal_apply_style:c {l_@@_nib_style_ \int_use:N \l_@@_tmpb_int} + + \spath_initialpoint:Nn \l_@@_tmpa_tl {####1} + \tl_set_eq:NN \l_@@_tmp_patha_tl \l_@@_tmp_path_tl + \spath_translate:NV \l_@@_tmp_patha_tl \l_@@_tmpa_tl + + \int_compare:nTF {\tl_count:n {####1} == 3} + { + \cal_at_least_three:N \l_@@_tmp_patha_tl + \spath_protocol_path:V \l_@@_tmp_patha_tl + + \tikz@options + \dim_set:Nn \l_@@_line_width_dim {\pgflinewidth} + \cal_maybe_taper:N \l_@@_tmp_patha_tl + } + { + \spath_weld:Nn \l_@@_tmp_patha_tl {####1} + \spath_weld:NV \l_@@_tmp_patha_tl \l_@@_tmp_rpath_tl + \spath_reverse:Nn \l_@@_tmp_rpathb_tl {####1} + \spath_weld:NV \l_@@_tmp_patha_tl \l_@@_tmp_rpathb_tl + + \tl_clear:N \l_@@_tmpa_tl + \tl_set:Nn \l_@@_tmpa_tl {fill=\pgfkeysvalueof{/tikz/pen~colour},draw=none} + \tl_if_exist:cT {l_@@_stroke_style_ \int_use:N \l_@@_tmpa_int} + { + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_stroke_style_ \int_use:N \l_@@_tmpa_int} + } + \tl_if_exist:cT {l_@@_stroke_inline_style_ \int_use:N \l_@@_tmpa_int} + { + \tl_put_right:Nn \l_@@_tmpa_tl {,} + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_stroke_inline_style_ \int_use:N \l_@@_tmpa_int} + } + \tl_if_exist:cT {l_@@_nib_style_ \int_use:N \l_@@_tmpb_int} + { + \tl_put_right:Nn \l_@@_tmpa_tl {,} + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_nib_style_ \int_use:N \l_@@_tmpb_int} + } + \spath_tikz_path:VV \l_@@_tmpa_tl \l_@@_tmp_patha_tl + + } + \pgfsys@endscope + \group_end: + } + + \bool_if:NT \l_@@_annotate_bool + { + \seq_get_right:NN #2 \l_@@_tmpa_tl + \spath_finalpoint:NV \l_@@_tmpa_tl \l_@@_tmpa_tl + \spath_translate:NV \l_@@_tmp_path_tl \l_@@_tmpa_tl + \tikz@scan@one@point\pgfutil@firstofone\pgfkeysvalueof{/tikz/annotation~shift} + + \spath_translate:Nnn \l_@@_tmp_path_tl {\pgf@x} {\pgf@y} + + \pgfkeysgetvalue{/tikz/annotation~style}{\l_@@_tmpa_tl} + \spath_tikz_path:VV \l_@@_tmpa_tl \l_@@_tmp_path_tl + + \spath_finalpoint:NV \l_@@_tmpa_tl \l_@@_tmp_path_tl + + \exp_last_unbraced:NV \pgfqpoint \l_@@_tmpa_tl + \begin{scope}[reset~ cm] + \node[every~annotation~node/.try,tl~use:c = {l_@@_annotation_style_ \int_use:N \l_@@_tmpa_int _tl}] at (\pgf@x,\pgf@y) {\int_use:N \l_@@_tmpa_int}; + \end{scope} + } + } + } +} +\cs_generate_variant:Nn \cal_path_create:NN {Nc} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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 \g_@@_path_component_int + \cal_orig_moveto:n {#1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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}[internal]{\cal_at_least_three:Nn} +% 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_protected_nopar:Npn \cal_at_least_three:Nn #1#2 +{ + \spath_reallength:Nn \l_@@_tmpa_int {#2} + \tl_clear:N \l_@@_tmpb_tl + \tl_set:Nn \l_@@_tmpb_tl {#2} + \int_compare:nTF {\l_@@_tmpa_int = 1} + { + \spath_split_at:Nn \l_@@_tmpb_tl {2/3} + \spath_split_at:Nn \l_@@_tmpb_tl {1/2} + } + { + \int_compare:nT {\l_@@_tmpa_int = 2} + { + \spath_split_at:Nn \l_@@_tmpb_tl {1.5} + \spath_split_at:Nn \l_@@_tmpb_tl {.5} + } + } + \tl_set_eq:NN #1 \l_@@_tmpb_tl +} +\cs_generate_variant:Nn \cal_at_least_three:Nn {NV} +\cs_new_protected_nopar:Npn \cal_at_least_three:N #1 +{ + \cal_at_least_three:NV #1#1 +} +\cs_generate_variant:Nn \cal_at_least_three:N {c} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\cal_maybe_taper:N} +% Possibly tapers the path, depending on the booleans. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \cal_maybe_taper:N #1 +{ + \tl_set_eq:NN \l_@@_tmpa_tl #1 + + \bool_if:NT \l_@@_taper_start_bool + { + + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpa_tl {2}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpa_tl {3}} + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {4}} + + \tl_case:NnF \l_@@_tmpb_tl + { + \c_spath_lineto_tl + { + + \bool_set_true:N \l_@@_taperable_bool + \dim_set:Nn \l_@@_tmpg_dim {\tl_item:Nn \l_@@_tmpa_tl {5}} + \dim_set:Nn \l_@@_tmph_dim {\tl_item:Nn \l_@@_tmpa_tl {6}} + \dim_set:Nn \l_@@_tmpc_dim {(2\l_@@_tmpa_dim + \l_@@_tmpg_dim)/3} + \dim_set:Nn \l_@@_tmpd_dim {(2\l_@@_tmpb_dim + \l_@@_tmph_dim)/3} + \dim_set:Nn \l_@@_tmpe_dim {(\l_@@_tmpa_dim + 2\l_@@_tmpg_dim)/3} + \dim_set:Nn \l_@@_tmpf_dim {(\l_@@_tmpb_dim + 2\l_@@_tmph_dim)/3} + \prg_replicate:nn {4} + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_put_left:NV \l_@@_tmpa_tl \c_spath_moveto_tl + } + \c_spath_curvetoa_tl + { + \bool_set_true:N \l_@@_taperable_bool + \dim_set:Nn \l_@@_tmpc_dim {\tl_item:Nn \l_@@_tmpa_tl {5}} + \dim_set:Nn \l_@@_tmpd_dim {\tl_item:Nn \l_@@_tmpa_tl {6}} + \dim_set:Nn \l_@@_tmpe_dim {\tl_item:Nn \l_@@_tmpa_tl {8}} + \dim_set:Nn \l_@@_tmpf_dim {\tl_item:Nn \l_@@_tmpa_tl {9}} + \dim_set:Nn \l_@@_tmpg_dim {\tl_item:Nn \l_@@_tmpa_tl {11}} + \dim_set:Nn \l_@@_tmph_dim {\tl_item:Nn \l_@@_tmpa_tl {12}} + \prg_replicate:nn {10} + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_put_left:NV \l_@@_tmpa_tl \c_spath_moveto_tl + } + } + { + \bool_set_false:N \l_@@_taperable_bool + } + + \bool_if:NT \l_@@_taperable_bool + { + \@@_taper_aux: + } + + } + + \bool_if:NT \l_@@_taper_end_bool + { + + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpa_tl {-2}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpa_tl {-1}} + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpa_tl {-3}} + + \tl_case:NnF \l_@@_tmpb_tl + { + \c_spath_lineto_tl + { + + \bool_set_true:N \l_@@_taperable_bool + \dim_set:Nn \l_@@_tmpg_dim {\tl_item:Nn \l_@@_tmpa_tl {-5}} + \dim_set:Nn \l_@@_tmph_dim {\tl_item:Nn \l_@@_tmpa_tl {-4}} + \dim_set:Nn \l_@@_tmpc_dim {(2\l_@@_tmpa_dim + \l_@@_tmpg_dim)/3} + \dim_set:Nn \l_@@_tmpd_dim {(2\l_@@_tmpb_dim + \l_@@_tmph_dim)/3} + \dim_set:Nn \l_@@_tmpe_dim {(\l_@@_tmpa_dim + 2\l_@@_tmpg_dim)/3} + \dim_set:Nn \l_@@_tmpf_dim {(\l_@@_tmpb_dim + 2\l_@@_tmph_dim)/3} + \tl_reverse:N \l_@@_tmpa_tl + \prg_replicate:nn {3} + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_reverse:N \l_@@_tmpa_tl + } + \c_spath_curveto_tl + { + \bool_set_true:N \l_@@_taperable_bool + \dim_set:Nn \l_@@_tmpc_dim {\tl_item:Nn \l_@@_tmpa_tl {-5}} + \dim_set:Nn \l_@@_tmpd_dim {\tl_item:Nn \l_@@_tmpa_tl {-4}} + \dim_set:Nn \l_@@_tmpe_dim {\tl_item:Nn \l_@@_tmpa_tl {-8}} + \dim_set:Nn \l_@@_tmpf_dim {\tl_item:Nn \l_@@_tmpa_tl {-7}} + \dim_set:Nn \l_@@_tmpg_dim {\tl_item:Nn \l_@@_tmpa_tl {-11}} + \dim_set:Nn \l_@@_tmph_dim {\tl_item:Nn \l_@@_tmpa_tl {-10}} + \tl_reverse:N \l_@@_tmpa_tl + \prg_replicate:nn {9} + { + \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} + } + \tl_reverse:N \l_@@_tmpa_tl + } + } + { + \bool_set_false:N \l_@@_taperable_bool + } + + \bool_if:NT \l_@@_taperable_bool + { + \@@_taper_aux: + } + + } + + \pgfsyssoftpath@setcurrentpath\l_@@_tmpa_tl + \pgfsetstrokecolor{\pgfkeysvalueof{/tikz/pen~colour}} + \pgfusepath{stroke} + +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\@@_taper_aux:} +% Auxiliary macro to avoid unnecessary code duplication. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_taper_aux: +{ + \tl_clear:N \l_@@_tmpb_tl + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_moveto_tl + + \fp_set:Nn \l_@@_tmpa_fp + { + \l_@@_tmpd_dim - \l_@@_tmpb_dim + } + \fp_set:Nn \l_@@_tmpb_fp + { + \l_@@_tmpa_dim - \l_@@_tmpc_dim + } + \fp_set:Nn \l_@@_tmpe_fp + { + (\l_@@_tmpa_fp^2 + \l_@@_tmpb_fp^2)^.5 + } + + \fp_set:Nn \l_@@_tmpa_fp {.5*\l_@@_taper_width_dim * \l_@@_tmpa_fp / \l_@@_tmpe_fp} + \fp_set:Nn \l_@@_tmpb_fp {.5*\l_@@_taper_width_dim * \l_@@_tmpb_fp / \l_@@_tmpe_fp} + + \fp_set:Nn \l_@@_tmpc_fp + { + \l_@@_tmph_dim - \l_@@_tmpf_dim + } + \fp_set:Nn \l_@@_tmpd_fp + { + \l_@@_tmpe_dim - \l_@@_tmpg_dim + } + \fp_set:Nn \l_@@_tmpe_fp + { + (\l_@@_tmpc_fp^2 + \l_@@_tmpd_fp^2)^.5 + } + + \fp_set:Nn \l_@@_tmpc_fp {.5*\l_@@_line_width_dim * \l_@@_tmpc_fp / \l_@@_tmpe_fp} + \fp_set:Nn \l_@@_tmpd_fp {.5*\l_@@_line_width_dim * \l_@@_tmpd_fp / \l_@@_tmpe_fp} + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpa_dim}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpb_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpc_dim}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpd_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpe_dim}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmpf_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpg_dim}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmph_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpg_dim - \fp_to_dim:n{ 1.32 * \l_@@_tmpd_fp}}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmph_dim + \fp_to_dim:n {1.32* \l_@@_tmpc_fp}}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpg_dim - \fp_to_dim:n {1.32 * \l_@@_tmpd_fp}}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmph_dim + \fp_to_dim:n {1.32 * \l_@@_tmpc_fp}}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpg_dim}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmph_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpc_fp + \l_@@_tmpe_dim}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpd_fp + \l_@@_tmpf_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpc_dim}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpd_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpa_dim}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpb_dim}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpa_dim + \fp_to_dim:n{ 1.32 * \l_@@_tmpb_fp}}} + {\dim_eval:n { -\fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpb_dim - \fp_to_dim:n {1.32* \l_@@_tmpa_fp}}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpa_dim + \fp_to_dim:n {1.32 * \l_@@_tmpb_fp}}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpb_dim - \fp_to_dim:n {1.32 * \l_@@_tmpa_fp}}} + } + + \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl + + \tl_put_right:Nx \l_@@_tmpb_tl + { + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpa_fp + \l_@@_tmpa_dim}} + {\dim_eval:n { \fp_to_dim:N \l_@@_tmpb_fp + \l_@@_tmpb_dim}} + } + + \pgfsyssoftpath@setcurrentpath\l_@@_tmpb_tl + \pgfsetfillcolor{\pgfkeysvalueof{/tikz/pen~colour}} + \pgfusepath{fill} +} +% \end{macrocode} +% \end{macro} +% +% Defines a copperplate pen. +% \begin{macrocode} +\tl_set:Nn \l_@@_tmpa_tl {\pgfsyssoftpath@movetotoken{0pt}{0pt}} +\spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpa_tl +\seq_gclear_new:N \g_@@_pen_copperplate_seq +\seq_gset_eq:NN \g_@@_pen_copperplate_seq \l_@@_tmpa_seq +% \end{macrocode} +% +% \begin{macro}{\CopperplatePath} +% This is used in the decorations section to convert a path to a copperplate path. +% \begin{macrocode} +\DeclareDocumentCommand \CopperplatePath { m } +{ + \spath_components_to_seq:NV \l_@@_tmpa_seq #1 + \cal_path_create:NN \l_@@_tmpa_seq \g_@@_pen_copperplate_seq +} +% \end{macrocode} +% \end{macro} +% +% \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 + \CopperplatePath{\cal@tmp@path} + } + \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 + \CopperplatePath{\cal@tmp@path} + } + \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 + \CopperplatePath{\cal@tmp@path} + } + \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} +% +% \begin{macrocode} +%<@@=knot> +% \end{macrocode} +% +% \subsection{Initialisation} +% +% We load the \Verb+spath3+ library and the \Verb+intersections+ TikZ library. +% Then we get going. +% \begin{macrocode} +\RequirePackage{spath3} +\usetikzlibrary{intersections,spath3} + +\ExplSyntaxOn + +\tl_new:N \l_@@_tmpa_tl +\tl_new:N \l_@@_tmpb_tl +\tl_new:N \l_@@_tmpc_tl +\tl_new:N \l_@@_tmpd_tl +\tl_new:N \l_@@_tmpg_tl +\tl_new:N \l_@@_redraws_tl +\tl_new:N \l_@@_clip_width_tl +\tl_new:N \l_@@_name_tl +\tl_new:N \l_@@_node_tl +\tl_new:N \l_@@_aux_tl +\tl_new:N \l_@@_auxa_tl +\tl_new:N \l_@@_prefix_tl + +\seq_new:N \l_@@_segments_seq + +\int_new:N \l_@@_tmpa_int +\int_new:N \l_@@_strands_int +\int_new:N \g_@@_intersections_int +\int_new:N \g_@@_filaments_int +\int_new:N \l_@@_component_start_int + +\fp_new:N \l_@@_tmpa_fp +\fp_new:N \l_@@_tmpb_fp + +\dim_new:N \l_@@_tmpa_dim +\dim_new:N \l_@@_tmpb_dim +\dim_new:N \l_@@_tolerance_dim +\dim_new:N \l_@@_clip_bg_radius_dim +\dim_new:N \l_@@_clip_draw_radius_dim + +\bool_new:N \l_@@_draft_bool +\bool_new:N \l_@@_ignore_ends_bool +\bool_new:N \l_@@_self_intersections_bool +\bool_new:N \l_@@_splits_bool +\bool_new:N \l_@@_super_draft_bool + +\bool_new:N \l_@@_prepend_prev_bool +\bool_new:N \l_@@_append_next_bool +\bool_new:N \l_@@_skip_bool +\bool_new:N \l_@@_save_bool + +\seq_new:N \g_@@_nodes_seq + +\bool_set_true:N \l_@@_ignore_ends_bool +% \end{macrocode} +% +% Configuration is via TikZ keys and styles. +% \begin{macrocode} +\tikzset{ + spath/prefix/knot/.style={ + spath/set~ prefix=knot strand, + }, + spath/suffix/knot/.style={ + spath/set~ suffix={}, + }, + knot/.code={ + \tl_if_eq:nnTF {#1} {none} + { + \tikz@addmode{\tikz@mode@doublefalse} + } + { + \tikz@addmode{\tikz@mode@doubletrue} + \tl_if_eq:nnTF {\pgfkeysnovalue} {#1} + { + \tikz@addoption{\pgfsetinnerstrokecolor{.}} + } + { + \pgfsetinnerstrokecolor{#1} + } + \tikz@addoption{ + \pgfsetstrokecolor{knotbg} + } + \tl_set:Nn \tikz@double@setup{ + \pgfsetinnerlinewidth{\pgflinewidth} + \pgfsetlinewidth{\dim_eval:n {\tl_use:N \l_@@_gap_tl \pgflinewidth}} + } + } + }, + knot~ gap/.store~ in=\l_@@_gap_tl, + knot~ gap=3, + knot~ diagram/.is~family, + knot~ diagram/.unknown/.code={ + \tl_set_eq:NN \l_@@_tmpa_tl \pgfkeyscurrentname + \pgfkeysalso{ + /tikz/\l_@@_tmpa_tl=#1 + } + }, + background~ colour/.code={% + \colorlet{knotbg}{#1}% + }, + background~ color/.code={% + \colorlet{knotbg}{#1}% + }, + background~ colour=white, + knot~ diagram, + name/.store~ in=\l_@@_name_tl, + name={knot}, + save~ intersections/.is~ choice, + save~ intersections/.default=true, + save~ intersections/true/.code={ + \bool_set_true:N \l_@@_save_bool + }, + save~ intersections/false/.code={ + \bool_set_false:N \l_@@_save_bool + }, + every~ strand/.style={draw}, + ignore~ endpoint~ intersections/.code={ + \tl_if_eq:nnTF {#1} {true} + { + \bool_set_true:N \l_@@_ignore_ends_bool + } + { + \bool_set_false:N \l_@@_ignore_ends_bool + } + }, + ignore~ endpoint~ intersections/.default=true, + consider~ self~ intersections/.is~choice, + consider~ self~ intersections/true/.code={ + \bool_set_true:N \l_@@_self_intersections_bool + \bool_set_true:N \l_@@_splits_bool + }, + consider~ self~ intersections/false/.code={ + \bool_set_false:N \l_@@_self_intersections_bool + \bool_set_false:N \l_@@_splits_bool + }, + consider~ self~ intersections/no~ splits/.code={ + \bool_set_true:N \l_@@_self_intersections_bool + \bool_set_false:N \l_@@_splits_bool + }, + consider~ self~ intersections/.default={true}, + clip~ radius/.code={ + \dim_set:Nn \l_@@_clip_bg_radius_dim {#1} + \dim_set:Nn \l_@@_clip_draw_radius_dim {#1+2pt} + }, + clip~ draw~ radius/.code={ + \dim_set:Nn \l_@@_clip_draw_radius_dim {#1} + }, + clip~ background~ radius/.code={ + \dim_set:Nn \l_@@_clip_bg_radius_dim {#1} + }, + clip~ radius=10pt, + end~ tolerance/.code={ + \dim_set:Nn \l_@@_tolerance_dim {#1} + }, + end~ tolerance=14pt, + clip/.style={ + clip + }, + background~ clip/.style={ + clip + }, + clip~ width/.code={ + \tl_set:Nn \l_@@_clip_width_tl {#1} + }, + clip~ width=3, + flip~ crossing/.code={% + \tl_clear_new:c {l_@@_crossing_#1} + \tl_set:cn {l_@@_crossing_#1} {x} + }, + ignore~ crossing/.code={% + \tl_clear_new:c {l_@@_ignore_crossing_#1} + \tl_set:cn {l_@@_ignore_crossing_#1} {x} + }, + draft~ mode/.is~ choice, + draft~ mode/off/.code={% + \bool_set_false:N \l_@@_draft_bool + \bool_set_false:N \l_@@_super_draft_bool + }, + draft~ mode/crossings/.code={% + \bool_set_true:N \l_@@_draft_bool + \bool_set_false:N \l_@@_super_draft_bool + }, + draft~ mode/strands/.code={% + \bool_set_true:N \l_@@_draft_bool + \bool_set_true:N \l_@@_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}[internal]{\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}[internal]{\strand} +% This is how the user specifies a strand of the knot. +% \begin{macrocode} +\NewDocumentCommand \strand { O{} } +{ + \int_incr:N \l_@@_strands_int + \tl_clear_new:c {l_@@_options_strand \int_use:N \l_@@_strands_int} + \tl_set:cn {l_@@_options_strand \int_use:N \l_@@_strands_int} {#1} + \path[#1,spath/set~ name=knot,spath/save=\int_use:N \l_@@_strands_int] +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{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}[internal]{\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_@@_strands_int + \tl_clear:N \l_@@_redraws_tl + \seq_gclear:N \g_@@_nodes_seq +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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_@@_strands_int} \knot_draw_strand:n +% \end{macrocode} +% In super draft mode we don't do anything else. +% \begin{macrocode} + \bool_if:NF \l_@@_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_@@_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_@@_self_intersections_bool + { + \knot_split_strands: + \int_set_eq:NN \l_@@_tmpa_int \g_@@_filaments_int + \tl_set:Nn \l_@@_prefix_tl {filament} + } + { + \int_set_eq:NN \l_@@_tmpa_int \l_@@_strands_int + \tl_set:Nn \l_@@_prefix_tl {strand} + } +% \end{macrocode} +% Initialise the intersection count. +% \begin{macrocode} + \int_gzero:N \g_@@_intersections_int +% \end{macrocode} +% If in draft mode we label the intersections, otherwise we just stick a coordinate at each one. +% \begin{macrocode} + \tl_clear:N \l_@@_node_tl + \bool_if:NT \l_@@_draft_bool + { + \tl_set:Nn \l_@@_node_tl { + \exp_not:N \node[coordinate, + pin={[node~ contents={\int_use:N \g_@@_intersections_int},knot~ diagram/draft/crossing~ label, knot~ diagram/draft/crossing~ \int_use:N \g_@@_intersections_int \c_space_tl label/.try] + }] + } + } +% \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_@@_tmpa_int - 1} \l_@@_tmpa_tl + { + \int_step_variable:nnnNn {\tl_use:N \l_@@_tmpa_tl + 1} {1} {\l_@@_tmpa_int} \l_@@_tmpb_tl + { + \knot_intersections:VV \l_@@_tmpa_tl \l_@@_tmpb_tl + } + } +% \end{macrocode} +% If any redraws were requested, do them here. +% \begin{macrocode} + \tl_use:N \l_@@_redraws_tl +% \end{macrocode} +% Draw the crossing nodes +% \begin{macrocode} + \seq_use:Nn \g_@@_nodes_seq {} + } +% \end{macrocode} +% Close the scope +% \begin{macrocode} + \endpgfscope +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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: + \spath_bake_round:c {knot strand #1} + \tl_set:Nn \l_@@_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_options_strand #1} + \tl_put_right:Nn \l_@@_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try} + \spath_tikz_path:Vv \l_@@_tmpa_tl {knot strand #1} + \group_end: + \endpgfscope +} +\cs_generate_variant:Nn \tl_put_right:Nn {Nv} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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_@@_draft_bool + { + \spath_finalpoint:Nv \l_@@_tmpb_tl {knot strand #1} + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpb_tl {1}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpb_tl {2}} + \node[knot~ diagram/draft/strand~label] at (\l_@@_tmpa_dim,\l_@@_tmpb_dim) {#1}; + \spath_initialpoint:Nv \l_@@_tmpb_tl {knot strand #1} + \dim_set:Nn \l_@@_tmpa_dim {\tl_item:Nn \l_@@_tmpb_tl {1}} + \dim_set:Nn \l_@@_tmpb_dim {\tl_item:Nn \l_@@_tmpb_tl {2}} + \node[knot~ diagram/draft/strand~label] at (\l_@@_tmpa_dim,\l_@@_tmpb_dim) {#1}; + } + \bool_if:nT { + \l_@@_self_intersections_bool + && + \l_@@_splits_bool + } + { + \tl_clear:N \l_@@_tmpa_tl + \spath_segments_to_seq:Nv \l_@@_segments_seq {knot strand #1} + \seq_map_function:NN \l_@@_segments_seq \knot_split_self_intersects:N + \tl_set_eq:cN {knot strand #1} \l_@@_tmpa_tl + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\knot_split_self_intersects:N} +% 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:N #1 +{ + \tl_set:Nx \l_@@_tmpc_tl {\tl_item:nn {#1} {4}} + \tl_case:NnF \l_@@_tmpc_tl + { + \c_spath_curvetoa_tl + { + \fp_set:Nn \l_@@_tmpa_fp + { + (\tl_item:nn {#1} {3} - 3 * \tl_item:nn {#1} {6} + 3 * \tl_item:nn {#1} {9} - \tl_item:nn {#1} {12}) + * + (3 * \tl_item:nn {#1} {8} - 3 * \tl_item:nn {#1} {11}) + - + (\tl_item:nn {#1} {2} - 3 * \tl_item:nn {#1} {5} + 3 * \tl_item:nn {#1} {8} - \tl_item:nn {#1} {11}) + * + (3 * \tl_item:nn {#1} {9} - 3 * \tl_item:nn {#1} {12}) + } + \fp_set:Nn \l_@@_tmpb_fp + { + (\tl_item:nn {#1} {2} - 3 * \tl_item:nn {#1} {5} + 3 * \tl_item:nn {#1} {8} - \tl_item:nn {#1} {11}) + * + (3 * \tl_item:nn {#1} {6} - 6 * \tl_item:nn {#1} {9} + 3 * \tl_item:nn {#1} {12}) + - + (\tl_item:nn {#1} {3} - 3 * \tl_item:nn {#1} {6} + 3 * \tl_item:nn {#1} {9} - \tl_item:nn {#1} {12}) + * + (3 * \tl_item:nn {#1} {5} - 6 * \tl_item:nn {#1} {8} + 3 * \tl_item:nn {#1} {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:NNnV \l_@@_tmpc_tl \l_@@_tmpd_tl {#1} \l_@@_tmpa_fp + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpd_tl {\tl_tail:N \l_@@_tmpd_tl} + \tl_set:Nx \l_@@_tmpd_tl {\tl_tail:N \l_@@_tmpd_tl} + \tl_set:Nx \l_@@_tmpd_tl {\tl_tail:N \l_@@_tmpd_tl} + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpc_tl + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpd_tl + } + { + \tl_set:Nn \l_@@_tmpc_tl {#1} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpc_tl + } + } + { + \tl_set:Nn \l_@@_tmpc_tl {#1} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpc_tl + } + } + \c_spath_lineto_tl + { + \tl_set:Nn \l_@@_tmpc_tl {#1} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpc_tl + } + } + { + \tl_put_right:Nn \l_@@_tmpa_tl {#1} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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_@@_tmpa_tl \l_@@_prefix_tl + \tl_put_right:Nn \l_@@_tmpa_tl {#1} + \tl_set_eq:NN \l_@@_tmpb_tl \l_@@_prefix_tl + \tl_put_right:Nn \l_@@_tmpb_tl {#2} + \tl_set_eq:Nc \l_@@_tmpc_tl {knot \tl_use:N \l_@@_tmpa_tl} + \tl_set_eq:Nc \l_@@_tmpd_tl {knot \tl_use:N \l_@@_tmpb_tl} + + \bool_if:nTF { + \l_@@_save_bool + && + \tl_if_exist_p:c {knot~ intersections~ \tl_use:N \l_@@_name_tl - \tl_use:N \l_@@_tmpa_tl - \tl_use:N \l_@@_tmpb_tl} + } + { + \tl_use:c {knot~ intersections~ \tl_use:N \l_@@_name_tl - \tl_use:N \l_@@_tmpa_tl - \tl_use:N \l_@@_tmpb_tl} + } + { +\pgfintersectionofpaths{\pgfsetpath\l_@@_tmpc_tl}{\pgfsetpath\l_@@_tmpd_tl} + + } + + \int_compare:nT {\pgfintersectionsolutions > 0} + { + \int_step_function:nnnN {1} {1} {\pgfintersectionsolutions} \knot_do_intersection:n + } + + \knot_save_intersections:VV \l_@@_tmpa_tl \l_@@_tmpb_tl + \group_end: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\knot_save_intersections:nn} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \knot_save_intersections:nn #1#2 +{ + \bool_if:NT \l_@@_save_bool + { + \tl_clear:N \l_@@_aux_tl + \tl_put_right:Nn \l_@@_aux_tl + { + \def\pgfintersectionsolutions + } + \tl_put_right:Nx \l_@@_aux_tl + { + {\int_eval:n {\pgfintersectionsolutions}} + } + \int_compare:nT {\pgfintersectionsolutions > 0} + { + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfpointintersectionsolution{##1} + \dim_set:Nn \l_@@_tmpa_dim {\pgf@x} + \dim_set:Nn \l_@@_tmpb_dim {\pgf@y} + \tl_put_right:Nn \l_@@_aux_tl + { + \expandafter\def\csname pgfpoint@intersect@solution@##1\endcsname + } + \tl_put_right:Nx \l_@@_aux_tl + { + {\exp_not:N \pgf@x=\dim_use:N \l_@@_tmpa_dim\exp_not:N\relax\exp_not:N \pgf@y =\dim_use:N \l_@@_tmpb_dim\relax} + } + } + \tl_set:Nn \l_@@_auxa_tl {\expandafter \gdef \csname knot~ intersections~} + \tl_put_right:Nx \l_@@_auxa_tl {\tl_use:N \l_@@_name_tl - #1 - #2} + \tl_put_right:Nn \l_@@_auxa_tl {\endcsname} + \tl_put_right:Nx \l_@@_auxa_tl {{\tl_to_str:N \l_@@_aux_tl}} + \protected@write\@auxout{}{\tl_to_str:N \l_@@_auxa_tl} + } + } +} +\cs_generate_variant:Nn \knot_save_intersections:nn {VV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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_@@_tmpa_dim {\pgf@x} + \dim_set:Nn \l_@@_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_@@_skip_bool + \bool_if:NT \l_@@_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_@@_tmpc_tl {knot previous} + \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpa_tl + \tl_set:Nv \l_@@_tmpc_tl \l_@@_tmpc_tl + \tl_if_eq:NNT \l_@@_tmpc_tl \l_@@_tmpb_tl + { + \knot_test_endpoint:VnT \l_@@_tmpb_tl {final point} + { + \bool_set_true:N \l_@@_skip_bool + } + } + + \tl_set:Nn \l_@@_tmpc_tl {knot previous} + \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpb_tl + \tl_set:Nv \l_@@_tmpc_tl \l_@@_tmpc_tl + \tl_if_eq:NNT \l_@@_tmpc_tl \l_@@_tmpa_tl + { + \knot_test_endpoint:VnT \l_@@_tmpa_tl {final point} + { + \bool_set_true:N \l_@@_skip_bool + } + } + } +% \end{macrocode} +% The user can also say that end points of filaments (or strands) should simply be ignored anyway. +% \begin{macrocode} + \bool_if:NT \l_@@_ignore_ends_bool + { + \knot_test_endpoint:VnT \l_@@_tmpa_tl {initial point} + { + \bool_set_true:N \l_@@_skip_bool + } + \knot_test_endpoint:VnT \l_@@_tmpa_tl {final point} + { + \bool_set_true:N \l_@@_skip_bool + } + \knot_test_endpoint:VnT \l_@@_tmpb_tl {initial point} + { + \bool_set_true:N \l_@@_skip_bool + } + \knot_test_endpoint:VnT \l_@@_tmpb_tl {final point} + { + \bool_set_true:N \l_@@_skip_bool + } + } +% \end{macrocode} +% Assuming that we passed all the above tests, we render the crossing. +% \begin{macrocode} + \bool_if:NF \l_@@_skip_bool + { + + \int_gincr:N \g_@@_intersections_int +% \end{macrocode} +% This is the intersection test. +% If the intersection finder finds too many, it might be useful to ignore some. +% \begin{macrocode} + \bool_if:nF + { + \tl_if_exist_p:c {l_@@_ignore_crossing_ \int_use:N + \g_@@_intersections_int} + && + ! \tl_if_empty_p:c {l_@@_ignore_crossing_ \int_use:N + \g_@@_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_@@_crossing_ \int_use:N + \g_@@_intersections_int} + && + ! \tl_if_empty_p:c {l_@@_crossing_ \int_use:N + \g_@@_intersections_int} + } + { + \tl_set_eq:NN \l_@@_tmpg_tl \l_@@_tmpb_tl + } + { + \tl_set_eq:NN \l_@@_tmpg_tl \l_@@_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_@@_self_intersections_bool + { + \knot_test_endpoint:VnT \l_@@_tmpg_tl {initial point} + { + \bool_set_true:N \l_@@_prepend_prev_bool + } + { + \bool_set_false:N \l_@@_prepend_prev_bool + } + \knot_test_endpoint:VnT \l_@@_tmpg_tl {final point} + { + \bool_set_true:N \l_@@_append_next_bool + } + { + \bool_set_false:N \l_@@_append_next_bool + } +% \end{macrocode} +% If either of those tests succeeded, do the appending or prepending. +% \begin{macrocode} + \bool_if:nT + { + \l_@@_prepend_prev_bool || \l_@@_append_next_bool + } + { + \tl_clear_new:c {knot \tl_use:N \l_@@_prefix_tl -1} + \tl_set_eq:cc {knot \tl_use:N \l_@@_prefix_tl -1} {knot \tl_use:N \l_@@_tmpg_tl} + + \tl_clear_new:c {l_@@_options_ \tl_use:N \l_@@_prefix_tl -1} + \tl_set_eq:cc {l_@@_options_ \tl_use:N \l_@@_prefix_tl -1} {l_@@_options_ \tl_use:N \l_@@_tmpg_tl} + + \bool_if:nT + { + \l_@@_prepend_prev_bool + && + \tl_if_exist_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + && + !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + } + { + \spath_prepend_no_move:cv {knot \tl_use:N \l_@@_prefix_tl -1} {knot \tl_use:c {knot previous \tl_use:N \l_@@_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_@@_splits_bool + && + \tl_if_exist_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + && + !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + } + { + \knot_test_endpoint:vnT {knot previous \tl_use:N \l_@@_tmpg_tl} {initial point} + { + + \spath_prepend_no_move:cv {knot \tl_use:N \l_@@_prefix_tl -1} {knot \tl_use:c {knot previous \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}}} + \tl_set_eq:Nc \l_@@_tmpa_tl {knot \tl_use:N \l_@@_prefix_tl -1} + } + } + } +% \end{macrocode} +% Now the same for appending. +% \begin{macrocode} + \bool_if:nT + { + \l_@@_append_next_bool + && + \tl_if_exist_p:c {knot next \tl_use:N \l_@@_tmpg_tl} + && + !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + } + { + \spath_append_no_move:cv {knot \tl_use:N \l_@@_prefix_tl -1} {knot \tl_use:c {knot next \tl_use:N \l_@@_tmpg_tl}} + \bool_if:nT + { + \l_@@_splits_bool + && + \tl_if_exist_p:c {knot previous \tl_use:N + \l_@@_tmpg_tl} + && + !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl} + } + { + \knot_test_endpoint:vnT {knot previous \tl_use:N \l_@@_tmpg_tl} {final point} + { + \spath_append_no_move:cv {knot \tl_use:N \l_@@_prefix_tl -1} {knot \tl_use:c {knot next \tl_use:c {knot next \tl_use:N \l_@@_tmpg_tl}}} + + } + } + } + + \tl_set:Nn \l_@@_tmpg_tl {\tl_use:N \l_@@_prefix_tl -1} + } + } +% \end{macrocode} +% Now we render the crossing. +% \begin{macrocode} + \pgfscope + \group_begin: + \tikzset{knot~ diagram/every~ intersection/.try, every~ intersection/.try, knot~ diagram/intersection~ \int_use:N \g_@@_intersections_int/.try} + \knot_draw_crossing:VVV \l_@@_tmpg_tl \l_@@_tmpa_dim \l_@@_tmpb_dim + \coordinate (\l_@@_name_tl \c_space_tl \int_use:N \g_@@_intersections_int) at (\dim_use:N \l_@@_tmpa_dim, \dim_use:N \l_@@_tmpb_dim); + \group_end: + \endpgfscope +% \end{macrocode} +% This ends the boolean as to whether to consider the intersection at all +% \begin{macrocode} + } +% \end{macrocode} +% And possibly stick a coordinate with a label at the crossing. +% \begin{macrocode} + \tl_if_empty:NF \l_@@_node_tl + { + \seq_gpush:Nx \g_@@_nodes_seq { \l_@@_node_tl at (\dim_use:N \l_@@_tmpa_dim, \dim_use:N \l_@@_tmpb_dim) {};} + } + } +} + +\cs_generate_variant:Nn \knot_intersections:nn {VV} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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 { \l_@@_tmpa_dim - \tl_item:Nn #1 {1}} + + + \dim_abs:n { \l_@@_tmpb_dim - \tl_item:Nn #1 {2}} + < + \l_@@_tolerance_dim + } + { + \prg_return_true: + } + { + \prg_return_false: + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\knot_test_endpoint:nn} +% Wrapper around the above. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \knot_test_endpoint:nn #1#2 {T,F,TF} +{ + \use:c {spath_#2:Nv} \l_@@_tmpd_tl {knot #1} + \knot_test_endpoint:NTF \l_@@_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}[internal]{\knot_draw_crossing:nnn} +% This is the code that actually renders a crossing. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \knot_draw_crossing:nnn #1#2#3 +{ + \group_begin: + \pgfscope + \path[knot~ diagram/background~ clip] (#2, #3) circle[radius=\l_@@_clip_bg_radius_dim]; + + \tl_set:Nn \l_@@_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_if_exist:cT {l_@@_options_ #1} + { + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_options_ #1} + } + \tl_put_right:Nn \l_@@_tmpa_tl {,knotbg,line~ width= \tl_use:N \l_@@_clip_width_tl * \pgflinewidth} + \spath_tikz_path:Vv \l_@@_tmpa_tl {knot #1} + + \endpgfscope + + \pgfscope + \path[knot~ diagram/clip] (#2, #3) circle[radius=\l_@@_clip_draw_radius_dim]; + + \tl_set:Nn \l_@@_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_if_exist:cT {l_@@_options_ #1} + { + \tl_put_right:Nv \l_@@_tmpa_tl {l_@@_options_ #1} + } + \tl_put_right:Nn \l_@@_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try} + \spath_tikz_path:Vv \l_@@_tmpa_tl {knot #1} + + \endpgfscope + \group_end: +} + +\cs_generate_variant:Nn \knot_draw_crossing:nnn {nVV, VVV} + +\cs_new_protected_nopar:Npn \knot_draw_crossing:nn #1#2 +{ + \tikz@scan@one@point\pgfutil@firstofone #2 \relax + \knot_draw_crossing:nVV {#1} \pgf@x \pgf@y +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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 \g_@@_filaments_int + \int_step_function:nnnN {1} {1} {\l_@@_strands_int} \knot_split_strand:n + \int_step_function:nnnN {1} {1} {\g_@@_filaments_int} \knot_compute_nexts:n +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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}[internal]{\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_@@_component_start_int \g_@@_filaments_int + \int_incr:N \l_@@_component_start_int + \tl_set_eq:Nc \l_@@_tmpa_tl {l_@@_options_strand #1} + \spath_segments_to_seq:Nv \l_@@_segments_seq {knot strand #1} + \seq_map_function:NN \l_@@_segments_seq \knot_save_filament:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\knot_save_filament:N} +% Saves a filament as a new \Verb+spath+ object. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \knot_save_filament:N #1 +{ + \tl_set:Nx \l_@@_tmpb_tl {\tl_item:nn {#1} {4}} + \tl_case:NnF \l_@@_tmpb_tl + { + \c_spath_moveto_tl + { + \int_compare:nT {\l_@@_component_start_int < \g_@@_filaments_int} + { + \int_set_eq:NN \l_@@_component_start_int \g_@@_filaments_int + } + } + \c_spath_lineto_tl + { + \int_gincr:N \g_@@_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g_@@_filaments_int} + \tl_set:cn {knot filament \int_use:N \g_@@_filaments_int} {#1} + + \tl_clear_new:c {l_@@_options_filament \int_use:N \g_@@_filaments_int} + \tl_set_eq:cN {l_@@_options_filament \int_use:N \g_@@_filaments_int} \l_@@_tmpa_tl + + \tl_clear_new:c {knot previous filament \int_use:N \g_@@_filaments_int} + \int_compare:nF {\l_@@_component_start_int == \g_@@_filaments_int} + { + \tl_set:cx {knot previous filament \int_use:N \g_@@_filaments_int} {filament \int_eval:n {\g_@@_filaments_int - 1}} + } + } + \c_spath_curvetoa_tl + { + \int_gincr:N \g_@@_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g_@@_filaments_int} + \tl_set:cn {knot filament \int_use:N \g_@@_filaments_int} {#1} + \tl_clear_new:c {l_@@_options_filament \int_use:N \g_@@_filaments_int} + \tl_set_eq:cN {l_@@_options_filament \int_use:N \g_@@_filaments_int} \l_@@_tmpa_tl + + \tl_clear_new:c {knot previous filament \int_use:N \g_@@_filaments_int} + \int_compare:nF {\l_@@_component_start_int == \g_@@_filaments_int} + { + \tl_set:cx {knot previous filament \int_use:N \g_@@_filaments_int} {filament \int_eval:n {\g_@@_filaments_int - 1}} + } + } + \c_spath_closepath_tl + { + \int_gincr:N \g_@@_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g_@@_filaments_int} + \tl_clear:N \l_@@_tmpa_tl + \tl_put_right:Nx {\tl_item:nn {#1} {1}\tl_item:nn {#1} {2}\tl_item:nn {#1} {3}} + \tl_put_right:NV \l_@@_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx {\tl_item:nn {#1} {5}\tl_item:nn {#1} {6}} + + \tl_set:cV {knot filament \int_use:N \g_@@_filaments_int} \l_@@_tmpa_tl + \tl_set_eq:cN {l_@@_options_filament \int_use:N \g_@@_filaments_int} \l_@@_tmpa_tl + \tl_clear_new:c {knot previous filament \int_use:N \g_@@_filaments_int} + \int_compare:nF {\l_@@_component_start_int == \g_@@_filaments_int} + { + \tl_set:cx {knot previous filament \int_use:N \g_@@_filaments_int} {filament \int_eval:n {\g_@@_filaments_int - 1}} + } + \tl_set:cx {knot previous filament \int_use:N \l_@@_component_start_int} {filament \int_use:N \g_@@_filaments_int} + } + } + { + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\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_@@_redraws_tl {\knot_draw_crossing:nn} + \tl_put_right:Nx \l_@@_redraws_tl { + {strand #1} {#2}% {\dim_use:N \pgf@x} {\dim_use:N \pgf@y} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +%<@@=> +% +% \begin{macro}[internal]{\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}[internal]{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}[internal]{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}[internal]{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}[internal]{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}[internal]{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_code.ins index b49c85b6e71..6c191765e5e 100644 --- a/Master/texmf-dist/source/latex/spath3/spath3.ins +++ b/Master/texmf-dist/source/latex/spath3/spath3_code.ins @@ -1,24 +1,24 @@ %% -%% This is file `spath3.ins', +%% This is file `spath3_code.ins', %% generated with the docstrip utility. %% %% The original source files were: %% -%% spath3.dtx (with options: `install') +%% spath3_code.dtx (with options: `install') %% ---------------------------------------------------------------- %% spath3 --- Functions for manipulating PGF soft paths -%% E-mail: stacey@math.ntnu.no +%% E-mail: loopspace@mathforge.org %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- %% -\input docstrip.tex +\input l3docstrip.tex \keepsilent \askforoverwritefalse \preamble ---------------------------------------------------------------- spath3 --- Functions for manipulating PGF soft paths -E-mail: stacey@math.ntnu.no +E-mail: loopspace@mathforge.org Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt ---------------------------------------------------------------- @@ -26,7 +26,7 @@ See http://www.latex-project.org/lppl.txt \endpreamble \postamble -Copyright (C) 2011-2019 by Andrew Stacey <stacey@math.ntnu.no> +Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> This work may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either @@ -41,19 +41,22 @@ Andrew Stacey. This work consists of the files spath3.dtx calligraphy_doc.tex knots_doc.tex + spath3.tex and the derived files spath3.ins, spath3_code.pdf, spath3.sty, tikzlibrarycalligraphy.code.tex tikzlibraryknots.code.tex + tikzlibraryspath3.code.tex calligraphy.pdf knots.pdf + spath3.pdf README \endpostamble \usedir{tex/latex/spath3} \generate{ - \file{\jobname.sty}{\from{\jobname.dtx}{spath3}} + \file{spath3.sty}{\from{\jobname.dtx}{spath3}} } \generate{ \file{tikzlibrarycalligraphy.code.tex}{\from{\jobname.dtx}{calligraphy}} @@ -61,9 +64,12 @@ and the derived files spath3.ins, \generate{ \file{tikzlibraryknots.code.tex}{\from{\jobname.dtx}{knots}} } +\generate{ + \file{tikzlibraryspath3.code.tex}{\from{\jobname.dtx}{tikzspath3}} +} \endbatchfile %% -%% Copyright (C) 2011-2019 by Andrew Stacey <stacey@math.ntnu.no> +%% Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either @@ -78,14 +84,17 @@ and the derived files spath3.ins, %% This work consists of the files spath3.dtx %% calligraphy_doc.tex %% knots_doc.tex +%% spath3.tex %% and the derived files spath3.ins, %% spath3_code.pdf, %% spath3.sty, %% tikzlibrarycalligraphy.code.tex %% tikzlibraryknots.code.tex +%% tikzlibraryspath3.code.tex %% calligraphy.pdf %% knots.pdf +%% spath3.pdf %% README %% %% -%% End of file `spath3.ins'. +%% End of file `spath3_code.ins'. diff --git a/Master/texmf-dist/tex/latex/spath3/spath3.sty b/Master/texmf-dist/tex/latex/spath3/spath3.sty index 43fd64cf5e2..155441947b0 100644 --- a/Master/texmf-dist/tex/latex/spath3/spath3.sty +++ b/Master/texmf-dist/tex/latex/spath3/spath3.sty @@ -4,10 +4,10 @@ %% %% The original source files were: %% -%% spath3.dtx (with options: `spath3') +%% spath3_code.dtx (with options: `spath3') %% ---------------------------------------------------------------- %% spath3 --- Functions for manipulating PGF soft paths -%% E-mail: stacey@math.ntnu.no +%% E-mail: loopspace@mathforge.org %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- @@ -15,335 +15,610 @@ \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} \RequirePackage{pgf} -\ProvidesExplPackage {spath3} {2019/02/12} {1.2} {Functions for +\ProvidesExplPackage {spath3} {2021/01/19} {2.0} {Functions for manipulating PGF soft paths} \RequirePackage{xparse} +\cs_new_protected:Nn \__spath_tl_put_right_braced:Nn +{ + \tl_put_right:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \__spath_tl_put_right_braced:Nn { NV, cV, cv, Nx, cx } + +\cs_new_protected:Nn \__spath_tl_gput_right_braced:Nn +{ + \tl_gput_right:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \__spath_tl_gput_right_braced:Nn { NV, cV, cv, Nx, cx } +\cs_new_protected:Nn \__spath_tl_put_left_braced:Nn +{ + \tl_put_left:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \__spath_tl_put_left_braced:Nn { NV, cV, cv, Nx, cx } + +\cs_new_protected:Nn \__spath_tl_gput_left_braced:Nn +{ + \tl_gput_left:Nn #1 { { #2 } } +} +\cs_generate_variant:Nn \__spath_tl_gput_left_braced:Nn { NV, cV, cv, Nx, cx } \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 +\tl_new:N \l__spath_tmpe_tl + +\seq_new:N \l__spath_tmpa_seq +\seq_new:N \l__spath_tmpb_seq + +\tl_new:N \g__spath_output_tl +\int_new:N \g__spath_output_int +\seq_new:N \g__spath_output_seq + \dim_new:N \l__spath_tmpa_dim \dim_new:N \l__spath_tmpb_dim +\dim_new:N \l__spath_move_x_dim +\dim_new:N \l__spath_move_y_dim \fp_new:N \l__spath_tmpa_fp \fp_new:N \l__spath_tmpb_fp \int_new:N \l__spath_tmpa_int -\int_new:N \g__spath_map_int -\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_new:N \g__spath_closepath_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} -\tl_set:Nn \g__spath_closepath_tl {\pgfsyssoftpath@closepathtoken} -\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} -} -\cs_new_nopar:Npn \spath_new:n #1 -{ - \prop_new:c {l__spath_#1} -} -\cs_new_nopar:Npn \spath_clear:n #1 -{ - \prop_gclear:c {l__spath_#1} -} -\cs_new_nopar:Npn \spath_clear_new:n #1 -{ - \prop_gclear_new:c {l__spath_#1} -} -\cs_new_nopar:Npn \spath_show:n #1 -{ - \prop_show:c {l__spath_#1} -} -\cs_new_nopar:Npn \spath_put:nnn #1#2#3 -{ - \prop_gput:cnn {l__spath_#1} {#2} {#3} -} -\cs_new_nopar:Npn \spath_remove:nn #1#2 -{ - \prop_gremove:cn {l__spath_#1} {#2} -} -\cs_new_nopar:Npn \__spath_get:nn #1#2 -{ - \prop_item:cn {l__spath_#1} {#2} -} -\cs_new_nopar:Npn \__spath_get:nnN #1#2#3 + +\bool_new:N \g__spath_output_bool +\bool_new:N \l__spath_closed_bool +\tl_const:Nn \c_spath_moveto_tl {\pgfsyssoftpath@movetotoken} +\tl_const:Nn \c_spath_lineto_tl {\pgfsyssoftpath@linetotoken} +\tl_const:Nn \c_spath_curveto_tl {\pgfsyssoftpath@curvetotoken} +\tl_const:Nn \c_spath_curvetoa_tl {\pgfsyssoftpath@curvetosupportatoken} +\tl_const:Nn \c_spath_curvetob_tl {\pgfsyssoftpath@curvetosupportbtoken} +\tl_const:Nn \c_spath_closepath_tl {\pgfsyssoftpath@closepathtoken} +\int_new:N \g__spath_anon_int +\int_gzero:N \g__spath_anon_int +\tl_new:N \l__spath_itera_tl +\tl_new:N \l__spath_iterb_tl +\tl_new:N \l__spath_iterc_tl +\tl_new:N \l__spath_iterd_tl +\tl_new:N \l__spath_iterp_tl +\dim_new:N \l__spath_itera_dim +\dim_new:N \l__spath_iterb_dim +\seq_new:N \l__spath_iter_seq +\msg_new:nnn { spath3 } { unknown path construction } { The~ path~ construction~ element~ #1~ is~ not~ currently~ supported.} +\cs_new_protected_nopar:Npn \__spath_segments_to_seq:n #1 { - \prop_get:cnN {l__spath_#1} {#2} #3 + \group_begin: + \tl_set:Nn \l__spath_itera_tl {#1} + \tl_clear:N \l__spath_iterb_tl + \seq_clear:N \l__spath_iter_seq + \dim_zero:N \l__spath_itera_dim + \dim_zero:N \l__spath_iterb_dim + + \bool_until_do:nn { + \tl_if_empty_p:N \l__spath_itera_tl + } + { + \tl_set:Nx \l__spath_iterc_tl {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + \tl_case:NnF \l__spath_iterc_tl + { + \c_spath_moveto_tl + { + \tl_set_eq:NN \l__spath_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_itera_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_iterb_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_set:Nx \l__spath_iterd_tl {\tl_head:N \l__spath_itera_tl} + \tl_if_eq:NNF \l__spath_iterd_tl \c_spath_moveto_tl + { + \tl_clear:N \l__spath_iterb_tl + } + + } + + \c_spath_lineto_tl + { + \tl_set_eq:NN \l__spath_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_iterb_tl + { + {\dim_use:N \l__spath_itera_dim} + {\dim_use:N \l__spath_iterb_dim} + } + \tl_put_right:NV \l__spath_iterb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_itera_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_iterb_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + } + + \c_spath_curvetoa_tl + { + \tl_set_eq:NN \l__spath_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_iterb_tl + { + {\dim_use:N \l__spath_itera_dim} + {\dim_use:N \l__spath_iterb_dim} + } + \tl_put_right:NV \l__spath_iterb_tl \c_spath_curvetoa_tl + + \prg_replicate:nn {2} { + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + \tl_put_right:Nx \l__spath_iterb_tl {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + } + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_itera_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_iterb_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + } + + \c_spath_closepath_tl + { + \tl_set_eq:NN \l__spath_iterb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_iterb_tl + { + {\dim_use:N \l__spath_itera_dim} + {\dim_use:N \l__spath_iterb_dim} + } + \tl_put_right:NV \l__spath_iterb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_itera_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_iterb_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + } + + } + { + + \tl_set_eq:NN \l__spath_iterb_tl \l__spath_iterc_tl + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_itera_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + \tl_put_right:Nx \l__spath_iterb_tl {{\tl_head:N \l__spath_itera_tl}} + \dim_set:Nn \l__spath_iterb_dim {\tl_head:N \l__spath_itera_tl} + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + + } + + \tl_if_empty:NF \l__spath_iterb_tl + { + \seq_put_right:NV \l__spath_iter_seq \l__spath_iterb_tl + } + \tl_clear:N \l__spath_iterb_tl + } + + \seq_gclear:N \g__spath_output_seq + \seq_gset_eq:NN \g__spath_output_seq \l__spath_iter_seq + \group_end: } -\prg_new_conditional:Npnn \spath_if_in:nn #1#2 {p, T, F, TF} +\cs_new_protected_nopar:Npn \spath_segments_to_seq:Nn #1#2 { - \prop_if_in:cnTF {l__spath_#1} {#2} - { \prg_return_true: } - { \prg_return_false: } + \__spath_segments_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_set_eq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_generate_variant:Nn \__prop_split:NnTF {cnTF} -\prg_new_protected_conditional:Npnn \__spath_get:nnN #1#2#3 {T, F, TF} +\cs_generate_variant:Nn \spath_segments_to_seq:Nn {NV, cn, cV, Nv, cv} +\cs_new_protected_nopar:Npn \spath_segments_gto_seq:Nn #1#2 { - \__prop_split:cnTF {l__spath_#1} {#2} - { - \tl_set:Nn #3 {##2} - \prg_return_true: - } - { \prg_return_false: } + \__spath_segments_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_gset_eq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_generate_variant:Nn \spath_put:nnn {nnV, nnx, nno} -\cs_generate_variant:Nn \__spath_get:nn {Vn} -\cs_generate_variant:Nn \__spath_get:nnN {VnN} -\prg_new_conditional:Npnn \spath_if_exist:n #1 {p,T,F,TF} +\cs_generate_variant:Nn \spath_segments_gto_seq:Nn {NV, cn, cV, Nv, cv} +\cs_new_protected_nopar:Npn \__spath_components_to_seq:n #1 { - \prop_if_exist:cTF {l__spath_#1} - { - \prg_return_true: - } - { - \prg_return_false: + \group_begin: + \tl_set:Nn \l__spath_itera_tl {#1} + \seq_clear:N \l__spath_iter_seq + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} + \tl_put_right:NV \l__spath_itera_tl \c_spath_moveto_tl + \tl_set_eq:NN \l__spath_iterb_tl \c_spath_moveto_tl + \bool_do_until:nn { + \tl_if_empty_p:N \l__spath_itera_tl } -} -\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} + \tl_set:Nx \l__spath_iterc_tl {\tl_head:N \l__spath_itera_tl} + \tl_if_eq:NNT \l__spath_iterc_tl \c_spath_moveto_tl + { + \seq_put_right:NV \l__spath_iter_seq \l__spath_iterb_tl + \tl_clear:N \l__spath_iterb_tl + } + \tl_if_single:NTF \l__spath_iterc_tl + { + \tl_put_right:NV \l__spath_iterb_tl \l__spath_iterc_tl + } { - \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl - \spath_put:nnV {#2} {##1} \l__spath_tmpa_tl + \tl_put_right:Nx \l__spath_iterb_tl {{\l__spath_iterc_tl}} } + \tl_set:Nx \l__spath_itera_tl {\tl_tail:N \l__spath_itera_tl} } -} -\cs_new_protected_nopar:Npn \spath_get_current_path:n #1 -{ - \pgfsyssoftpath@getcurrentpath\l__spath_tmpa_tl - \spath_clear_new:n {#1} - \spath_put:nnV {#1} {path} \l__spath_tmpa_tl -} -\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 -} -\cs_new_protected_nopar:Npn \spath_use_path:nn #1#2 -{ - \spath_set_current_path:n {#1} - \pgfusepath{#2} + \seq_gclear:N \g__spath_output_seq + \seq_gset_eq:NN \g__spath_output_seq \l__spath_iter_seq + \group_end: } -\cs_new_protected_nopar:Npn \spath_protocol_path:n #1 +\cs_new_protected_nopar:Npn \spath_components_to_seq:Nn #1#2 { - \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_components_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_set_eq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2 +\cs_generate_variant:Nn \spath_components_to_seq:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_gto_seq:Nn #1#2 { - \path[#1] \pgfextra{ - \spath_get:nnN {#2} {path} \l__spath_tmpa_tl - \pgfsyssoftpath@setcurrentpath \l__spath_tmpa_tl - }; + \__spath_components_to_seq:n {#2} + \seq_clear_new:N #1 + \seq_gset_eq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_generate_variant:Nn \spath_tikz_path:nn {Vn} -\cs_new_nopar:Npn \spath_get:nn #1#2 +\cs_generate_variant:Nn \spath_components_gto_seq:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_to_clist:Nn #1#2 { - \spath_if_in:nnF {#1} {#2} - { - \cs_if_exist_use:cT {spath_generate_#2:n} {{#1}} - } - \__spath_get:nn {#1} {#2} + \__spath_components_to_seq:n {#2} + \clist_clear_new:N #1 + \clist_set_from_seq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_new_nopar:Npn \spath_get:nnN #1#2#3 +\cs_generate_variant:Nn \spath_components_to_clist:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_components_gto_clist:Nn #1#2 { - \spath_if_in:nnF {#1} {#2} - { - \cs_if_exist_use:cT {spath_generate_#2:n} {{#1}} - } - \__spath_get:nnN {#1} {#2} #3 + \__spath_components_to_seq:n {#2} + \clist_clear_new:N #1 + \clist_gset_from_seq:NN #1 \g__spath_output_seq + \seq_gclear:N \g__spath_output_seq } -\cs_generate_variant:Nn \spath_get:nnN {VnN} -\cs_new_nopar:Npn \spath_generate_length:n #1 +\cs_generate_variant:Nn \spath_components_gto_clist:Nn {NV, cn, cV, cv, Nv} +\cs_new_protected_nopar:Npn \spath_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 }} + \int_eval:n {\tl_count:n {#1} / 3} } -\cs_new_nopar:Npn \spath_generate_reallength:n #1 +\cs_generate_variant:Nn \spath_length:n {V} +\cs_new_protected_nopar:Npn \__spath_reallength:n #1 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl + \group_begin: \int_set:Nn \l__spath_tmpa_int {0} - \tl_map_inline:Nn \l__spath_tmpa_tl { - \tl_if_eq:nnT {##1} {\pgfsyssoftpath@linetotoken} + \tl_map_inline:nn {#1} { + \tl_set:Nn \l__spath_tmpc_tl {##1} + \tl_case:NnT \l__spath_tmpc_tl { - \int_incr:N \l__spath_tmpa_int + \c_spath_lineto_tl {} + \c_spath_curveto_tl {} + \c_spath_closepath_tl {} } - \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} + \int_gzero:N \g__spath_output_int + \int_gset_eq:NN \g__spath_output_int \l__spath_tmpa_int + \group_end: +} +\cs_new_protected_nopar:Npn \spath_reallength:Nn #1#2 +{ + \__spath_reallength:n {#2} + \int_set_eq:NN #1 \g__spath_output_int + \int_gzero:N \g__spath_output_int +} +\cs_generate_variant:Nn \spath_reallength:Nn {NV, cn, cV, Nv, cv} +\cs_new_protected_nopar:Npn \spath_greallength:Nn #1#2 +{ + \__spath_reallength:n {#2} + \int_gset_eq:NN #1 \g__spath_output_int + \int_gzero:N \g__spath_output_int } -\cs_new_nopar:Npn \spath_generate_numberofcomponents:n #1 +\cs_generate_variant:Nn \spath_greallength:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \__spath_numberofcomponents:n #1 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl + \group_begin: \int_set:Nn \l__spath_tmpa_int {0} - \tl_map_inline:Nn \l__spath_tmpa_tl { - \tl_if_eq:nnT {##1} {\pgfsyssoftpath@movetotoken} + \tl_map_inline:nn {#1} { + \tl_set:Nn \l__spath_tmpa_tl {##1} + \tl_case:Nn \l__spath_tmpa_tl { - \int_incr:N \l__spath_tmpa_int + \c_spath_moveto_tl + { + \int_incr:N \l__spath_tmpa_int + } } } - \spath_put:nnx {#1} {number of components} {\int_use:N \l__spath_tmpa_int} + \int_gzero:N \g__spath_output_int + \int_gset_eq:NN \g__spath_output_int \l__spath_tmpa_int + \group_end: } -\cs_new_nopar:Npn \spath_generate_initialpoint:n #1 +\cs_new_protected_nopar:Npn \spath_numberofcomponents:Nn #1#2 { - \__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 + \__spath_numberofcomponents:n {#2} + \int_set_eq:NN #1 \g__spath_output_int + \int_gzero:N \g__spath_output_int +} +\cs_generate_variant:Nn \spath_numberofcomponents:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gnumberofcomponents:Nn #1#2 +{ + \__spath_numberofcomponents:n {#2} + \int_gset_eq:NN #1 \g__spath_output_int + \int_gzero:N \g__spath_output_int } -\cs_new_nopar:Npn \spath_generate_finalpoint:n #1 +\cs_generate_variant:Nn \spath_gnumberofcomponents:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \__spath_initialpoint:n #1 { + \group_begin: \tl_clear:N \l__spath_tmpb_tl - \spath_if_in:nnTF {#1} {reverse path} + \tl_set:Nx \l__spath_tmpb_tl { - \__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}} + { \tl_item:nn {#1} {2} } + { \tl_item:nn {#1} {3} } } + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_initialpoint:Nn #1#2 +{ + \__spath_initialpoint:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_initialpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_ginitialpoint:Nn #1#2 +{ + \__spath_initialpoint:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_ginitialpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \__spath_finalpoint:n #1 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_reverse:N \l__spath_tmpa_tl + \tl_clear:N \l__spath_tmpb_tl + \tl_set:Nx \l__spath_tmpb_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}} + { \tl_item:Nn \l__spath_tmpa_tl {2} } + { \tl_item:Nn \l__spath_tmpa_tl {1} } } - \spath_put:nnV {#1} {final point} \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_finalpoint:Nn #1#2 +{ + \__spath_finalpoint:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_finalpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_gfinalpoint:Nn #1#2 +{ + \__spath_finalpoint:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\cs_generate_variant:Nn \spath_generate_finalpoint:n {V} -\cs_new_nopar:Npn \spath_generate_reversepath:n #1 +\cs_generate_variant:Nn \spath_gfinalpoint:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \__spath_reverse:n #1 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_clear:N \l__spath_tmpb_tl + \tl_clear:N \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 + + \tl_put_left:Nx \l__spath_tmpd_tl { {\dim_use:N \l__spath_tmpa_dim} {\dim_use:N \l__spath_tmpb_dim} } + + \bool_set_false:N \l__spath_closed_bool + \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:NnF \l__spath_tmpc_tl + + \tl_case:NnTF \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 } + \c_spath_moveto_tl { + + \bool_if:NT \l__spath_closed_bool + { + \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl + \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl} + \tl_put_right:Nx \l__spath_tmpd_tl + { + { \tl_head:N \l__spath_tmpd_tl } + { \tl_head:N \l__spath_tmpe_tl } + } + } + \bool_set_false:N \l__spath_closed_bool + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl + \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl + \tl_clear:N \l__spath_tmpd_tl + } + \c_spath_lineto_tl { + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_lineto_tl + } + \c_spath_curveto_tl { + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetoa_tl + } + \c_spath_curvetoa_tl { + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curveto_tl + } + \c_spath_curvetob_tl { + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetob_tl + } } { - \tl_show:N \l__spath_tmpc_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_tmpd_tl + { + {\dim_use:N \l__spath_tmpa_dim} + {\dim_use:N \l__spath_tmpb_dim} + } + } - \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_if_eq:NNTF \l__spath_tmpc_tl \c_spath_closepath_tl + { + \bool_set_true:N \l__spath_closed_bool + } + { + \msg_warning:nnx { spath3 } { unknown path construction } {\l__spath_tmpc_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_put_left:NV \l__spath_tmpb_tl \g__spath_moveto_tl - \spath_put:nnV {#1} {reverse path} \l__spath_tmpb_tl + + \bool_if:NT \l__spath_closed_bool + { + \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl + \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl} + \tl_put_right:Nx \l__spath_tmpd_tl + { + { \tl_head:N \l__spath_tmpd_tl } + { \tl_head:N \l__spath_tmpe_tl } + } + } + + \bool_set_false:N \l__spath_closed_bool + \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl + \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl + + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: } -\cs_new_nopar:Npn \spath_generate_initialaction:n #1 +\cs_new_protected_nopar:Npn \spath_reverse:Nn #1#2 { - \__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 + \__spath_reverse:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_generate_finalaction:n #1 +\cs_generate_variant:Nn \spath_reverse:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_reverse:N #1 { - \tl_clear:N \l__spath_tmpb_tl - \spath_if_in:nnTF {#1} {reverse path} + \spath_reverse:NV #1#1 +} +\cs_generate_variant:Nn \spath_reverse:N {c} +\cs_new_protected_nopar:Npn \spath_greverse:Nn #1#2 +{ + \__spath_reverse:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_greverse:Nn {NV, cn, cV, Nv} +\cs_new_protected_nopar:Npn \spath_greverse:N #1 +{ + \spath_greverse:NV #1#1 +} +\cs_generate_variant:Nn \spath_greverse:N {c} +\cs_new_protected_nopar:Npn \__spath_initialaction:n #1 +{ + \group_begin: + \tl_clear:N \l__spath_tmpa_tl + \int_compare:nT { - \__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_count:n {#1} > 3 } { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl - \tl_reverse:N \l__spath_tmpa_tl + \tl_set:Nx \l__spath_tmpa_tl + { + \tl_item:Nn {#1} {4} + } } - \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_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_initialaction:Nn #1#2 +{ + \__spath_initialaction:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_initialaction:Nn {NV} +\cs_new_protected_nopar:Npn \spath_ginitialaction:Nn #1#2 +{ + \__spath_initialaction:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_ginitialaction:Nn {NV} +\cs_new_protected_nopar:Npn \__spath_finalaction:n #1 +{ + \group_begin: + \tl_clear:N \l__spath_tmpb_tl + \int_compare:nT + { + \tl_count:n {#1} > 3 } - \tl_if_eq:NNT \l__spath_tmpa_tl \g__spath_curvetoa_tl { - \tl_set_eq:NN \l__spath_tmpa_tl \g__spath_curveto_tl + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_reverse:N \l__spath_tmpa_tl + \tl_set:Nx \l__spath_tmpb_tl + { + \tl_item:Nn \l__spath_tmpa_tl {3} + } + \tl_if_eq:NNT \l__spath_tmpb_tl \c_spath_curvetoa_tl + { + \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_curveto_tl + } } - \spath_put:nnV {#1} {final action} \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_finalaction:Nn #1#2 +{ + \__spath_finalaction:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_generate_minbb:n #1 +\cs_generate_variant:Nn \spath_finalaction:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gfinalaction:Nn #1#2 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl + \__spath_finalaction:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gfinalaction:Nn {NV} +\cs_new_protected_nopar:Npn \__spath_minbb:n #1 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} \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} @@ -365,11 +640,27 @@ manipulating PGF soft paths} {\dim_use:N \l__spath_tmpa_dim} {\dim_use:N \l__spath_tmpb_dim} } - \spath_put:nnV {#1} {min bb} \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_minbb:Nn #1#2 +{ + \__spath_minbb:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_minbb:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gminbb:Nn #1#2 +{ + \__spath_minbb:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_generate_maxbb:n #1 +\cs_generate_variant:Nn \spath_gminbb:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \__spath_maxbb:n #1 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} \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} @@ -391,1101 +682,2440 @@ manipulating PGF soft paths} {\dim_use:N \l__spath_tmpa_dim} {\dim_use:N \l__spath_tmpb_dim} } - \spath_put:nnV {#1} {max bb} \l__spath_tmpb_tl -} -\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 + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_maxbb:Nn #1#2 +{ + \__spath_maxbb:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_maxbb:Nn {NV, cn, cV} +\cs_new_protected_nopar:Npn \spath_gmaxbb:Nn #1#2 +{ + \__spath_maxbb:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gmaxbb:Nn {NV, cn, cV} +\int_set:Nn \l__spath_tmpa_int {\char_value_catcode:n {`@}} +\char_set_catcode_letter:N @ +\cs_new_protected_nopar:Npn \spath_save_to_aux:Nn #1#2 { + \tl_if_empty:nF {#2} { - {\dim_use:N \l__spath_tmpa_dim} - {\dim_use:N \l__spath_tmpb_dim} + \tl_clear:N \l__spath_tmpa_tl + \tl_put_right:Nn \l__spath_tmpa_tl { + \ExplSyntaxOn + \tl_clear:N #1 + \tl_set:Nn #1 {#2} + \ExplSyntaxOff + } + \protected@write\@auxout{}{ + \tl_to_str:N \l__spath_tmpa_tl + } } - - \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 +} +\char_set_catcode:nn {`@} {\l__spath_tmpa_int} +\cs_generate_variant:Nn \spath_save_to_aux:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_save_to_aux:N #1 +{ + \tl_if_exist:NT #1 { - {\dim_use:N \l__spath_tmpa_dim} - {\dim_use:N \l__spath_tmpb_dim} + \spath_save_to_aux:NV #1#1 } - - \tl_set:Nx \l__spath_ia_tl {\tl_head:N \l__spath_tmpa_tl} - +} +\cs_new_protected_nopar:Npn \__spath_translate:nnn #1#2#3 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_clear:N \l__spath_tmpb_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:NnF \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_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} - \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 {\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_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}} + \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_left:Nx \l__spath_rp_tl + \tl_put_right:Nx \l__spath_tmpb_tl { {\dim_use:N \l__spath_tmpa_dim} {\dim_use:N \l__spath_tmpb_dim} } + } + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_translate:Nnnn #1#2#3#4 +{ + \__spath_translate:nnn {#2}{#3}{#4} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_translate:Nnnn {NVxx, NVVV, NVnn} +\cs_new_protected_nopar:Npn \spath_translate:Nnn #1#2#3 +{ + \spath_translate:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_translate:Nnn {NVV, cnn, cVV} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nnnn #1#2#3#4 +{ + \__spath_translate:nnn {#2}{#3}{#4} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gtranslate:Nnnn {NVxx, NVVV, NVnn} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nnn #1#2#3 +{ + \spath_gtranslate:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_gtranslate:Nnn {NVV, cnn, cVV} +\cs_new_protected_nopar:Npn \spath_translate:Nn #1#2 +{ + \spath_translate:Nnn #1 #2 +} +\cs_generate_variant:Nn \spath_translate:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gtranslate:Nn #1#2 +{ + \spath_gtranslate:Nnn #1 #2 +} +\cs_generate_variant:Nn \spath_gtranslate:Nn {NV} +\cs_new_protected_nopar:Npn \__spath_scale:nnn #1#2#3 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \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} - \tl_set:Nx \l__spath_fp_tl + \fp_set:Nn \l__spath_tmpa_fp {\tl_head:N \l__spath_tmpa_tl * #2} + \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} + + \fp_set:Nn \l__spath_tmpb_fp {\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} + {\fp_to_dim:N \l__spath_tmpa_fp} + {\fp_to_dim:N \l__spath_tmpb_fp} } + } + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_scale:Nnnn #1#2#3#4 +{ + \__spath_scale:nnn {#2}{#3}{#4} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_scale:Nnnn {NVnn, Nnxx} +\cs_new_protected_nopar:Npn \spath_scale:Nnn #1#2#3 +{ + \spath_scale:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_scale:Nnn {cnn, cVV, NVV} +\cs_new_protected_nopar:Npn \spath_gscale:Nnnn #1#2#3#4 +{ + \__spath_scale:nnn {#2}{#3}{#4} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gscale:Nnnn {NVnn, Nnxx} +\cs_new_protected_nopar:Npn \spath_gscale:Nnn #1#2#3 +{ + \spath_gscale:NVnn #1#1{#2}{#3} +} +\cs_generate_variant:Nn \spath_gscale:Nnn {cnn, cVV, NVV} +\cs_new_protected_nopar:Npn \spath_scale:Nn #1#2 +{ + \spath_scale:Nnn #1 #2 +} + +\cs_generate_variant:Nn \spath_scale:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gscale:Nn #1#2 +{ + \spath_gscale:Nnn #1 #2 +} +\cs_generate_variant:Nn \spath_gscale:Nn {NV} +\cs_new_protected_nopar:Npn \__spath_transform:nnnnnnn #1#2#3#4#5#6#7 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \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} + \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_set:Nx \l__spath_tmpd_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:NV \l__spath_rp_tl \g__spath_moveto_tl + \fp_set:Nn \l__spath_tmpa_fp {\l__spath_tmpc_tl * #2 + \l__spath_tmpd_tl * #4 + #6} + \fp_set:Nn \l__spath_tmpb_fp {\l__spath_tmpc_tl * #3 + \l__spath_tmpd_tl * #5 + #7} + \tl_put_right:Nx \l__spath_tmpb_tl + { + {\fp_to_dim:N \l__spath_tmpa_fp} + {\fp_to_dim:N \l__spath_tmpb_fp} + } + } - \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_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_transform:Nnnnnnnn #1#2#3#4#5#6#7#8 +{ + \__spath_transform:nnnnnnn {#2}{#3}{#4}{#5}{#6}{#7}{#8} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_transform:Nnnnnnnn {NVnnnnnn, Nnxxxxxx, cnnnnnnn} +\cs_new_protected_nopar:Npn \spath_transform:Nnnnnnn #1#2#3#4#5#6#7 +{ + \spath_transform:NVnnnnnn #1#1{#2}{#3}{#4}{#5}{#6}{#7} +} +\cs_generate_variant:Nn \spath_transform:Nnnnnnn {cnnnnnn} +\cs_new_protected_nopar:Npn \spath_transform:Nnn #1#2#3 +{ + \spath_transform:Nnnnnnnn #1{#2}#3 +} +\cs_generate_variant:Nn \spath_transform:Nnn {cnn, cVn, NVn, NnV} +\cs_new_protected_nopar:Npn \spath_transform:Nn #1#2 +{ + \spath_transform:NVnnnnnn #1#1#2 +} +\cs_generate_variant:Nn \spath_transform:Nn {cn, cV, NV} - \tl_clear:N \l__spath_tmpb_tl - \tl_put_right:Nx \l__spath_tmpb_tl +\cs_new_protected_nopar:Npn \spath_gtransform:Nnnnnnnn #1#2#3#4#5#6#7#8 +{ + \__spath_transform:nnnnnnn {#2}{#3}{#4}{#5}{#6}{#7}{#8} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gtransform:Nnnnnnnn {NVnnnnnn, Nnxxxxxx, cnnnnnnn} +\cs_new_protected_nopar:Npn \spath_gtransform:Nnnnnnn #1#2#3#4#5#6#7 +{ + \spath_gtransform:NVnnnnnn #1#1{#2}{#3}{#4}{#5}{#6}{#7} +} +\cs_generate_variant:Nn \spath_gtransform:Nnnnnnn {cnnnnnn} +\cs_new_protected_nopar:Npn \spath_gtransform:Nnn #1#2#3 +{ + \spath_gtransform:Nnnnnnnn #1{#2}#3 +} +\cs_generate_variant:Nn \spath_gtransform:Nnn {cnn, cVn, NVn, NnV} +\cs_new_protected_nopar:Npn \spath_gtransform:Nn #1#2 +{ + \spath_gtransform:NVnnnnnn #1#1#2 +} +\cs_generate_variant:Nn \spath_gtransform:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \__spath_weld:nn #1#2 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_set:Nn \l__spath_tmpb_tl {#2} + + \spath_finalpoint:NV \l__spath_tmpc_tl \l__spath_tmpa_tl + \spath_initialpoint:NV \l__spath_tmpd_tl \l__spath_tmpb_tl + + \dim_set:Nn \l__spath_tmpa_dim { - {\dim_use:N \l__spath_minx_dim} - {\dim_use:N \l__spath_miny_dim} + \tl_item:Nn \l__spath_tmpc_tl {1} + - + \tl_item:Nn \l__spath_tmpd_tl {1} + } + \dim_set:Nn \l__spath_tmpb_dim + { + \tl_item:Nn \l__spath_tmpc_tl {2} + - + \tl_item:Nn \l__spath_tmpd_tl {2} } - \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 + \spath_translate:NVV \l__spath_tmpb_tl \l__spath_tmpa_dim \l__spath_tmpb_dim + + \prg_replicate:nn {3} { - {\dim_use:N \l__spath_maxx_dim} - {\dim_use:N \l__spath_maxy_dim} + \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl} } - \spath_put:nnV {#1} {max bb} \l__spath_tmpb_tl + \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: } -\cs_new_nopar:Npn \spath_translate:nnn #1#2#3 +\cs_new_protected_nopar:Npn \spath_weld: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 + \__spath_weld:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_weld:Nnn {NVV,NVn} +\cs_new_protected_nopar:Npn \spath_weld:Nn #1#2 +{ + \spath_weld:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_weld:Nn {NV, Nv, cV, cv} +\cs_new_protected_nopar:Npn \spath_gweld:Nnn #1#2#3 +{ + \__spath_weld:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gweld:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gweld:Nn #1#2 +{ + \spath_gweld:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gweld:Nn {NV, Nv, cV, cv} +\cs_new_protected_nopar:Npn \__spath_append_no_move:nn #1#2 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_set:Nn \l__spath_tmpb_tl {#2} + \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} - \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_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_append_no_move:Nnn #1#2#3 +{ + \__spath_append_no_move:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_append_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_append_no_move:Nn #1#2 +{ + \spath_append_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_gappend_no_move:Nnn #1#2#3 +{ + \__spath_append_no_move:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gappend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gappend_no_move:Nn #1#2 +{ + \spath_gappend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_append:Nnn #1#2#3 +{ + \tl_set:Nn #1 {#2} + \tl_put_right:Nn #1 {#3} +} +\cs_generate_variant:Nn \spath_append:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_append:Nn #1#2 +{ + \spath_append:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_append:Nn {NV, Nv} +\cs_new_protected_nopar:Npn \spath_gappend:Nnn #1#2#3 +{ + \tl_gset:Nn #1 {#2} + \tl_gput_right:Nn #1 {#3} +} +\cs_generate_variant:Nn \spath_gappend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gappend:Nn #1#2 +{ + \spath_gappend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv} +\cs_new_protected_nopar:Npn \spath_prepend_no_move:Nnn #1#2#3 +{ + \spath_append_no_move:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_prepend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_prepend_no_move:Nn #1#2 +{ + \spath_prepend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_prepend_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_gprepend_no_move:Nnn #1#2#3 +{ + \spath_gappend_no_move:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_gprepend_no_move:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gprepend_no_move:Nn #1#2 +{ + \spath_gprepend_no_move:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gprepend_no_move:Nn {NV, cv} +\cs_new_protected_nopar:Npn \spath_prepend:Nnn #1#2#3 +{ + \spath_append:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_prepend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_prepend:Nn #1#2 +{ + \spath_prepend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_prepend:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gprepend:Nnn #1#2#3 +{ + \spath_gappend:Nnn #1{#3}{#2} +} +\cs_generate_variant:Nn \spath_gprepend:Nnn {NVV, NVn} +\cs_new_protected_nopar:Npn \spath_gprepend:Nn #1#2 +{ + \spath_gprepend:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gprepend:Nn {NV} +\cs_new_protected_nopar:Npn \__spath_bake_round:n #1 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \pgf@@processround \l__spath_tmpa_tl\l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_bake_round:Nn #1#2 +{ + \__spath_bake_round:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_bake_round:Nn {NV} +\cs_new_protected_nopar:Npn \spath_bake_round:N #1 +{ + \spath_bake_round:NV #1#1 +} +\cs_generate_variant:Nn \spath_bake_round:N {c} +\cs_new_protected_nopar:Npn \spath_gbake_round:Nn #1#2 +{ + \__spath_bake_round:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gbake_round:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gbake_round:N #1 +{ + \spath_gbake_round:NV #1#1 +} +\cs_generate_variant:Nn \spath_gbake_round:N {c} +\cs_new_protected_nopar:Npn \__spath_close:n #1 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \spath_initialpoint:NV \l__spath_tmpb_tl \l__spath_tmpa_tl + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_closepath_tl + \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_close:Nn #1#2 +{ + \__spath_close:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_close:Nn {NV} +\cs_new_protected_nopar:Npn \spath_close:N #1 +{ + \spath_close:NV #1#1 +} +\cs_generate_variant:Nn \spath_close:N {c} +\cs_new_protected_nopar:Npn \spath_gclose:Nn #1#2 +{ + \__spath_close:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gclose:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gclose:N #1 +{ + \spath_gclose:NV #1#1 +} +\cs_generate_variant:Nn \spath_gclose:N {c} +\cs_new_protected_nopar:Npn \__spath_open:n #1 +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_clear:N \l__spath_tmpb_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l__spath_tmpa_tl } - \tl_map_inline:Nn \g__spath_path_attributes { - \spath_if_in:nnT {#1} {##1} + \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:NnF \l__spath_tmpc_tl { - \__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} + \c_spath_closepath_tl { - \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl + #2} + \bool_if:nF + { + \dim_compare_p:n + { + \l__spath_move_x_dim == \l__spath_tmpa_dim + } + && + \dim_compare_p:n + { + \l__spath_move_y_dim == \l__spath_tmpb_dim + } + } + { + \tl_put_right:NV \l__spath_tmpb_tl \c_spath_lineto_tl + + \tl_put_right:Nx \l__spath_tmpb_tl { + { \dim_use:N \l__spath_move_x_dim } + { \dim_use:N \l__spath_move_y_dim } + } + } + + \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_tmpb_dim {\tl_head:N \l__spath_tmpa_tl + #3} + \c_spath_moveto_tl { + \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl + + \dim_set:Nn \l__spath_move_x_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_move_y_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 - { - {\dim_use:N \l__spath_tmpa_dim} - {\dim_use:N \l__spath_tmpb_dim} + \tl_put_right:Nx \l__spath_tmpb_tl { + { \dim_use:N \l__spath_move_x_dim } + { \dim_use:N \l__spath_move_y_dim } } + + \dim_set_eq:NN \l__spath_tmpa_dim \l__spath_move_x_dim + \dim_set_eq:NN \l__spath_tmpb_dim \l__spath_move_y_dim + } + } + { + \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_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_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_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl + \group_end: } - -\cs_generate_variant:Nn \spath_translate:nnn {nxx} -\cs_new_nopar:Npn \spath_translate:nn #1#2 +\cs_new_protected_nopar:Npn \spath_open:Nn #1#2 { - \spath_translate:nnn {#1} #2 + \__spath_open:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } - -\cs_generate_variant:Nn \spath_translate:nn {nV} -\cs_new_nopar:Npn \spath_scale:nnn #1#2#3 +\cs_generate_variant:Nn \spath_open:Nn {NV} +\cs_new_protected_nopar:Npn \spath_open:N #1 +{ + \spath_open:NV #1#1 +} +\cs_new_protected_nopar:Npn \spath_gopen:Nn #1#2 +{ + \__spath_open:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gopen:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gopen:N #1 +{ + \spath_gopen:NV #1#1 +} +\cs_new_protected_nopar:Npn \__spath_remove_empty_components:n #1 { - \tl_map_inline:Nn \g__spath_moveable_attributes + \group_begin: + \spath_components_to_seq:Nn \l__spath_tmpa_seq {#1} + \tl_clear:N \l__spath_tmpa_tl + \seq_map_inline:Nn \l__spath_tmpa_seq { - \spath_if_in:nnT {#1} {##1} + \int_compare:nF { - \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl - - \fp_set:Nn \l__spath_tmpa_fp {\tl_head:N \l__spath_tmpa_tl * #2} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - \fp_set:Nn \l__spath_tmpb_fp {\tl_head:N \l__spath_tmpa_tl * #3} - \tl_clear:N \l__spath_tmpb_tl - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl + \tl_count:n {##1} == 3 + } + { + \tl_put_right:Nn \l__spath_tmpa_tl {##1} } } - \tl_map_inline:Nn \g__spath_path_attributes + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_remove_empty_components:Nn #1#2 +{ + \__spath_remove_empty_components:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_remove_empty_components:Nn {NV} +\cs_new_protected_nopar:Npn \spath_remove_empty_components:N #1 +{ + \spath_remove_empty_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_remove_empty_components:N {c} +\cs_new_protected_nopar:Npn \spath_gremove_empty_components:Nn #1#2 +{ + \__spath_remove_empty_components:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gremove_empty_components:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gremove_empty_components:N #1 +{ + \spath_gremove_empty_components:NV #1#1 +} +\cs_generate_variant:Nn \spath_gremove_empty_components:N {c} +\prg_new_protected_conditional:Npnn \spath_if_eq:nn #1#2 { T, F, TF } +{ + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_set:Nn \l__spath_tmpb_tl {#2} + \bool_gset_true:N \g__spath_tmpa_bool + \int_compare:nNnTF {\tl_count:N \l__spath_tmpa_tl} = {\tl_count:N \l__spath_tmpb_tl} { - \spath_if_in:nnT {#1} {##1} + \int_step_inline:nnnn {1} {3} {\tl_count:N \l__spath_tmpa_tl} { - \__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_set:Nx \l__spath_tmpc_tl {\tl_item:Nn \l__spath_tmpa_tl {##1}} + \tl_set:Nx \l__spath_tmpd_tl {\tl_item:Nn \l__spath_tmpb_tl {##1}} + \tl_if_eq:NNF \l__spath_tmpc_tl \l__spath_tmpd_tl + { + \bool_gset_false:N \g__spath_tmpa_bool } + \dim_set:Nn \l__spath_tmpa_dim {\tl_item:Nn \l__spath_tmpa_tl {##1+1}} + \dim_set:Nn \l__spath_tmpb_dim {\tl_item:Nn \l__spath_tmpb_tl {##1+1}} + \dim_compare:nF { \dim_abs:n { \l__spath_tmpa_dim - \l__spath_tmpb_dim} < 0.001pt } { - \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} - - \fp_set:Nn \l__spath_tmpa_fp {\tl_head:N \l__spath_tmpa_tl * #2} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - - \fp_set:Nn \l__spath_tmpb_fp {\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 - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } + \bool_gset_false:N \g__spath_tmpa_bool + } + \dim_set:Nn \l__spath_tmpa_dim {\tl_item:Nn \l__spath_tmpa_tl {##1+2}} + \dim_set:Nn \l__spath_tmpb_dim {\tl_item:Nn \l__spath_tmpb_tl {##1+2}} + \dim_compare:nF { \dim_abs:n { \l__spath_tmpa_dim - \l__spath_tmpb_dim} < 0.001pt } + { + \bool_gset_false:N \g__spath_tmpa_bool } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl } } + { + \bool_gset_false:N \g__spath_tmpa_bool + } + \group_end: + \bool_if:NTF \g__spath_tmpa_bool + { + \prg_return_true: + } + { + \prg_return_false: + } } -\cs_generate_variant:Nn \spath_scale:nnn {nxx} -\cs_new_nopar:Npn \spath_scale:nn #1#2 +\prg_generate_conditional_variant:Nnn \spath_if_eq:nn {VV, Vn, nV, vv} {TF, T, F} +\cs_new_protected_nopar:Npn \__spath_split_curve:nn #1#2 { - \spath_scale:nnn {#1} #2 -} + \group_begin: + \tl_set_eq:NN \l__spath_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl { + {\tl_item:nn {#1} {2}} + {\tl_item:nn {#1} {3}} + } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curvetoa_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } -\cs_generate_variant:Nn \spath_scale:nn {nV} -\cs_new_nopar:Npn \spath_transform:nnnnnnn #1#2#3#4#5#6#7 -{ - \tl_map_inline:Nn \g__spath_moveable_attributes + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curvetob_tl + \tl_put_right:Nx \l__spath_tmpa_tl { - \spath_if_in:nnT {#1} {##1} + {\fp_to_dim:n { - \__spath_get:nnN {#1} {##1} \l__spath_tmpa_tl - \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpb_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_head:N \l__spath_tmpa_tl} - \fp_set:Nn \l__spath_tmpa_fp {\l__spath_tmpa_tl * #2 + \l__spath_tmpb_tl * #3 + #6} - \fp_set:Nn \l__spath_tmpb_fp {\l__spath_tmpa_tl * #4 + \l__spath_tmpb_tl * #5 + #7} - \tl_clear:N \l__spath_tmpb_tl - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl - } + (1 - #2)^2 * \tl_item:nn {#1} {2} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {5} + (#2)^2 * \tl_item:nn {#1} {8} + }} + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {3} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {6} + (#2)^2 * \tl_item:nn {#1} {9} + }} } - \tl_map_inline:Nn \g__spath_path_attributes + + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl { - \spath_if_in:nnT {#1} {##1} + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {2} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {5} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {8} + (#2)^3 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n { - \__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 - } + (1 - #2)^3 * \tl_item:nn {#1} {3} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {6} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {9} + (#2)^3 * \tl_item:nn {#1} {12} + }} + } + + \tl_gclear:N \g__spath_output_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpa_tl + + \tl_clear:N \l__spath_tmpa_tl + \tl_set_eq:NN \l__spath_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n { - \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_set:Nx \l_tmpa_tl {\tl_head:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} - \tl_set:Nx \l_tmpb_tl {\tl_head:N \l__spath_tmpa_tl} - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} + (1 - #2)^3 * \tl_item:nn {#1} {2} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {5} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {8} + (#2)^3 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2)^3 * \tl_item:nn {#1} {3} + 3 * (1 - #2)^2 * (#2) * \tl_item:nn {#1} {6} + 3 * (1 - #2) * (#2)^2 * \tl_item:nn {#1} {9} + (#2)^3 * \tl_item:nn {#1} {12} + }} + } - \fp_set:Nn \l__spath_tmpa_fp {\l_tmpa_tl * #2 + \l_tmpb_tl * #3 + #6} - \fp_set:Nn \l__spath_tmpb_fp {\l_tmpa_tl * #4 + \l_tmpb_tl * #5 + #7} - \tl_put_right:Nx \l__spath_tmpb_tl - { - {\fp_to_dim:N \l__spath_tmpa_fp} - {\fp_to_dim:N \l__spath_tmpb_fp} - } - } - \spath_put:nnV {#1} {##1} \l__spath_tmpb_tl - } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curvetoa_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {5} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {8} + (#2)^2 * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2)^2 * \tl_item:nn {#1} {6} + 2 * (1 - #2) * (#2) * \tl_item:nn {#1} {9} + (#2)^2 * \tl_item:nn {#1} {12} + }} + } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curvetob_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {8} + (#2) * \tl_item:nn {#1} {11} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {9} + (#2) * \tl_item:nn {#1} {12} + }} + } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_curveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl { + {\tl_item:nn {#1} {11}} + {\tl_item:nn {#1} {12}} } -} -\cs_generate_variant:Nn \spath_transform:nnnnnnn {nxxxxxx} -\cs_new_nopar:Npn \spath_transform:nn #1#2 -{ - \spath_transform:nnnnnnn {#1} #2 + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpa_tl + \group_end: } - -\cs_generate_variant:Nn \spath_transform:nn {nV} -\cs_new_nopar:Npn \spath_reverse:n #1 +\cs_new_protected_nopar:Npn \spath_split_curve:NNnn #1#2#3#4 { - \spath_if_in:nnF {#1} {reverse path} { - \use:c {spath_generate_reverse path:n} {#1} - } - \spath_swap:nnn {#1} {path} {reverse path} - \spath_swap:nnn {#1} {initial point} {final point} - \spath_swap:nnn {#1} {initial action} {final action} + \__spath_split_curve:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_swap:nnn #1#2#3 +\cs_generate_variant:Nn \spath_split_curve:NNnn {NNnV, NNVn, NNVV} +\cs_new_protected_nopar:Npn \spath_gsplit_curve:NNnn #1#2#3#4 { - \__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:nn {#1} {#2}} - {\spath_put:nnV {#1} {#2} \l__spath_tmpb_tl} - \tl_if_empty:NTF \l__spath_tmpa_tl - {\spath_remove:nn {#1} {#3}} - {\spath_put:nnV {#1} {#3} \l__spath_tmpa_tl} + \__spath_split_curve:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_weld:nn #1#2 +\cs_generate_variant:Nn \spath_gsplit_curve:NNnn {NNnV, NNVn, NNVV} +\cs_new_protected_nopar:Npn \__spath_split_line: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} + \group_begin: + \tl_set_eq:NN \l__spath_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl { + {\tl_item:nn {#1} {2}} + {\tl_item:nn {#1} {3}} + } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } + \tl_gclear:N \g__spath_output_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpa_tl - \__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 + \tl_clear:N \l__spath_tmpa_tl + \tl_set_eq:NN \l__spath_tmpa_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_tmpa_tl + { + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {2} + (#2) * \tl_item:nn {#1} {5} + }} + {\fp_to_dim:n + { + (1 - #2) * \tl_item:nn {#1} {3} + (#2) * \tl_item:nn {#1} {6} + }} + } + \tl_put_right:NV \l__spath_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx \l__spath_tmpa_tl { + {\tl_item:nn {#1} {5}} + {\tl_item:nn {#1} {6}} + } - \spath_put:nnV {#1} {path} \l__spath_tmpa_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_split_line:NNnn #1#2#3#4 +{ + \__spath_split_line:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_split_line:NNnn {NNnV, NNVn, NNVV} +\cs_new_protected_nopar:Npn \spath_gsplit_line:NNnn #1#2#3#4 +{ + \__spath_split_line:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_line:NNnn {NNnV, NNVn, NNVV} +\int_new:N \l__spath_split_int +\int_new:N \l__spath_splitat_int +\fp_new:N \l__spath_split_fp +\bool_new:N \l__spath_split_bool +\tl_new:N \l__spath_split_path_tl +\tl_new:N \l__spath_split_patha_tl +\tl_new:N \l__spath_split_pathb_tl +\tl_new:N \l__spath_split_intoa_tl +\tl_new:N \l__spath_split_intob_tl +\dim_new:N \l__spath_splitx_dim +\dim_new:N \l__spath_splity_dim +\cs_new_protected_nopar:Npn \__spath_split_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l__spath_splitat_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l__spath_split_fp {#2 - floor(#2)} - \__spath_get:nnNTF {tmp_path} {final point} \l__spath_tmpa_tl + % Is split point near one end or other of a component? + \fp_compare:nT { - \spath_put:nnV {#1} {final point} \l__spath_tmpa_tl + \l__spath_split_fp < 0.01 } { - \spath_remove:nn {#1} {final point} + % Near the start, so we'll place it at the start + \fp_set:Nn \l__spath_split_fp {0} } - - \__spath_get:nnNTF {tmp_path} {final action} \l__spath_tmpa_tl + \fp_compare:nT { - \spath_put:nnV {#1} {final action} \l__spath_tmpa_tl + \l__spath_split_fp > 0.99 } { - \spath_remove:nn {#1} {final action} + % Near the end, so we'll place it at the end + \fp_set:Nn \l__spath_split_fp {0} + \int_incr:N \l__spath_splitat_int } - \__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} + \int_zero:N \l__spath_split_int + \bool_set_true:N \l__spath_split_bool - \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_set:Nn \l__spath_split_path_tl {#1} + \tl_clear:N \l__spath_split_patha_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 - } - } + \dim_zero:N \l__spath_splitx_dim + \dim_zero:N \l__spath_splity_dim - \__spath_get:nnNT {tmp_path} {max bb} \l__spath_tmpa_tl + \bool_until_do:nn { + \tl_if_empty_p:N \l__spath_split_path_tl + || + \int_compare_p:n { \l__spath_splitat_int == \l__spath_split_int } + } { - \__spath_get:nnNT {#1} {max bb} \l__spath_tmpb_tl + \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_split_path_tl} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + \tl_case:Nn \l__spath_tmpc_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 + \c_spath_lineto_tl { - {\dim_use:N \l__spath_tmpa_dim} - {\dim_use:N \l__spath_tmpb_dim} + \int_incr:N \l__spath_split_int + } + \c_spath_curvetoa_tl + { + \int_incr:N \l__spath_split_int } - \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 + \int_compare:nT { \l__spath_split_int < \l__spath_splitat_int } { - \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 + \tl_put_right:NV \l__spath_split_patha_tl \l__spath_tmpc_tl + + \tl_put_right:Nx \l__spath_split_patha_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \dim_set:Nn \l__spath_splitx_dim {\tl_head:N \l__spath_split_path_tl} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \tl_put_right:Nx \l__spath_split_patha_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \dim_set:Nn \l__spath_splity_dim {\tl_head:N \l__spath_split_path_tl} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } - \spath_put:nnV {#1} {reverse path} \l__spath_tmpa_tl } } - \__spath_get:nnNT {tmp_path} {length} \l__spath_tmpa_tl + \tl_clear:N \l__spath_split_pathb_tl + \tl_put_right:NV \l__spath_split_pathb_tl \c_spath_moveto_tl + \tl_put_right:Nx \l__spath_split_pathb_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 - } + {\dim_use:N \l__spath_splitx_dim} + {\dim_use:N \l__spath_splity_dim} } - \__spath_get:nnNT {tmp_path} {real length} \l__spath_tmpa_tl + \fp_compare:nTF + { + \l__spath_split_fp == 0 + } { - \__spath_get:nnNT {#1} {real length} \l__spath_tmpb_tl + \tl_set_eq:NN \l__spath_split_intob_tl \l__spath_split_pathb_tl + \tl_if_empty:NF \l__spath_split_path_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 + \tl_put_right:NV \l__spath_split_intob_tl \l__spath_tmpc_tl + \tl_put_right:NV \l__spath_split_intob_tl \l__spath_split_path_tl } } - - \__spath_get:nnNT {tmp_path} {number of components} \l__spath_tmpa_tl { - \__spath_get:nnNT {#1} {number of components} \l__spath_tmpb_tl + + \tl_case:Nn \l__spath_tmpc_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 + \c_spath_lineto_tl + { + \tl_put_right:NV \l__spath_split_pathb_tl \l__spath_tmpc_tl + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \spath_split_line:NNVV + \l__spath_split_intoa_tl + \l__spath_split_intob_tl + \l__spath_split_pathb_tl + \l__spath_split_fp + + \prg_replicate:nn {3} { + \tl_set:Nx \l__spath_split_intoa_tl {\tl_tail:N \l__spath_split_intoa_tl} + } + + \tl_put_right:NV \l__spath_split_patha_tl \l__spath_split_intoa_tl + \tl_put_right:NV \l__spath_split_intob_tl \l__spath_split_path_tl + } + \c_spath_curvetoa_tl + { + \tl_put_right:NV \l__spath_split_pathb_tl \l__spath_tmpc_tl + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \prg_replicate:nn {2} { + + \tl_put_right:Nx \l__spath_split_pathb_tl + { \tl_head:N \l__spath_split_path_tl } + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + + \tl_put_right:Nx \l__spath_split_pathb_tl + {{ \tl_head:N \l__spath_split_path_tl }} + \tl_set:Nx \l__spath_split_path_tl {\tl_tail:N \l__spath_split_path_tl } + } + + \spath_split_curve:NNVV + \l__spath_split_intoa_tl + \l__spath_split_intob_tl + \l__spath_split_pathb_tl \l__spath_split_fp + + \prg_replicate:nn {3} { + \tl_set:Nx \l__spath_split_intoa_tl {\tl_tail:N \l__spath_split_intoa_tl} + } + + \tl_put_right:NV \l__spath_split_patha_tl \l__spath_split_intoa_tl + \tl_put_right:NV \l__spath_split_intob_tl \l__spath_split_path_tl + } } } + \tl_gclear:N \g__spath_output_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_split_patha_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_split_intob_tl + \group_end: } -\cs_new_nopar:Npn \spath_prepend_no_move:nn #1#2 +\cs_new_protected_nopar:Npn \spath_split_at:NNnn #1#2#3#4 { - \spath_if_exist:nT {#2} + \__spath_split_at:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_split_at:NNnn {NNVn, NNVV, NNnV} +\cs_new_protected_nopar:Npn \spath_gsplit_at:NNnn #1#2#3#4 +{ + \__spath_split_at:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at:NNnn {NNVn, NNVV, NNnV} +\cs_new_protected_nopar:Npn \spath_split_at:Nnn #1#2#3 +{ + \__spath_split_at:nn {#2}{#3} + \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1} \tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_split_at:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_split_at:Nn #1#2 +{ + \spath_split_at:NVn #1#1{#2} +} +\cs_new_protected_nopar:Npn \spath_gsplit_at:Nnn #1#2#3 +{ + \__spath_split_at:nn {#2}{#3} + \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1} \tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gsplit_at:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_gsplit_at:Nn #1#2 +{ + \spath_gsplit_at:NVn #1#1{#2} +} +\tl_new:N \l__spath_shorten_fa_tl +\tl_new:N \l__spath_shorten_path_tl +\tl_new:N \l__spath_shorten_last_tl +\tl_new:N \l__spath_shorten_lasta_tl +\tl_new:N \l__spath_shorten_lastb_tl +\int_new:N \l__spath_shorten_int +\fp_new:N \l__spath_shorten_x_fp +\fp_new:N \l__spath_shorten_y_fp +\fp_new:N \l__spath_shorten_len_fp +\cs_new_protected_nopar:Npn \__spath_shorten_at_end:nn #1#2 +{ + \int_compare:nTF { - \__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 + \tl_count:n {#1} > 3 + } + { + \group_begin: + \tl_set:Nn \l__spath_shorten_path_tl {#1} + \tl_reverse:N \l__spath_shorten_path_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} - } + \tl_set:Nx \l__spath_shorten_fa_tl {\tl_item:Nn \l__spath_shorten_path_tl {3}} - \spath_if_in:nnTF {#2} {initial action} + \tl_clear:N \l__spath_shorten_last_tl + \tl_if_eq:NNTF \l__spath_shorten_fa_tl \c_spath_curveto_tl { - \__spath_get:nnN {#2} {initial action} \l__spath_tmpa_tl - \spath_put:nnV {#1} {initial action} \l__spath_tmpa_tl + \int_set:Nn \l__spath_shorten_int {3} } { - \spath_remove:nn {#1} {initial action} + \int_set:Nn \l__spath_shorten_int {1} } - \bool_if:nTF + \prg_replicate:nn { \l__spath_shorten_int } { - \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} + \tl_put_right:Nx \l__spath_shorten_last_tl + { + {\tl_head:N \l__spath_shorten_path_tl} + } + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl} + \tl_put_right:Nx \l__spath_shorten_last_tl + { + {\tl_head:N \l__spath_shorten_path_tl} + } + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl} + \tl_put_right:Nx \l__spath_shorten_last_tl + { + \tl_head:N \l__spath_shorten_path_tl + } + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl} } + + \tl_put_right:Nx \l__spath_shorten_last_tl { - \__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 }} + {\tl_item:Nn \l__spath_shorten_path_tl {1}} + {\tl_item:Nn \l__spath_shorten_path_tl {2}} } + \tl_put_right:NV \l__spath_shorten_last_tl \c_spath_moveto_tl + + \tl_reverse:N \l__spath_shorten_path_tl + + \fp_set:Nn \l__spath_shorten_x_fp { - \spath_remove:nn {#1} {real length} + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {4}} + - + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {1}} } - \bool_if:nTF + + \fp_set:Nn \l__spath_shorten_y_fp { - \spath_if_in_p:nn {#1} {number of components} - && - \spath_if_in_p:nn {#2} {number of components} + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {5}} + - + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {2}} } + + \fp_set:Nn \l__spath_shorten_len_fp { - \__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}} + sqrt( \l__spath_shorten_x_fp * \l__spath_shorten_x_fp + \l__spath_shorten_y_fp * \l__spath_shorten_y_fp ) } + + \fp_compare:nTF { - \spath_remove:nn {#1} {number of components} + \l__spath_shorten_len_fp > #2 } - \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} + + \fp_set:Nn \l__spath_shorten_len_fp + { + (\l__spath_shorten_len_fp - #2)/ \l__spath_shorten_len_fp } - } - { - \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} + + \tl_reverse:N \l__spath_shorten_last_tl + + \tl_if_eq:NNTF \l__spath_shorten_fa_tl \c_spath_curveto_tl + { + \fp_set:Nn \l__spath_shorten_len_fp + { + 1 - (1 -\l__spath_shorten_len_fp)/3 + } + \spath_split_curve:NNVV + \l__spath_shorten_lasta_tl + \l__spath_shorten_lastb_tl + \l__spath_shorten_last_tl + \l__spath_shorten_len_fp } + { + \spath_split_line:NNVV + \l__spath_shorten_lasta_tl + \l__spath_shorten_lastb_tl + \l__spath_shorten_last_tl + \l__spath_shorten_len_fp + } + + \prg_replicate:nn {3} + { + \tl_set:Nx \l__spath_shorten_lasta_tl {\tl_tail:N \l__spath_shorten_lasta_tl} + } + + \tl_put_right:NV \l__spath_shorten_path_tl \l__spath_shorten_lasta_tl + } { - \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} + + \int_compare:nT + { + \tl_count:N \l__spath_shorten_path_tl > 3 + } + { + \dim_set:Nn \l__spath_tmpa_dim {\fp_to_dim:n {#2 - \l__spath_shorten_len_fp } } + \spath_shorten_at_end:NV \l__spath_shorten_path_tl \l__spath_tmpa_dim + } } + \tl_gset_eq:NN \g__spath_output_tl \l__spath_shorten_path_tl + \group_end: } + { + \tl_gset:Nn \g__spath_output_tl {#1} + } +} +\cs_new_protected_nopar:Npn \spath_shorten_at_end:Nnn #1#2#3 +{ + \__spath_shorten_at_end:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_shorten_at_end:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_shorten_at_end:Nn #1#2 +{ + \spath_shorten_at_end:NVn #1#1{#2} } -\cs_new_nopar:Npn \spath_append_no_move:nn #1#2 +\cs_generate_variant:Nn \spath_shorten_at_end:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_gshorten_at_end:Nnn #1#2#3 { - \spath_if_exist:nT {#2} + \__spath_shorten_at_end:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gshorten_at_end:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_gshorten_at_end:Nn #1#2 +{ + \spath_gshorten_at_end:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gshorten_at_end:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \__spath_shorten_at_start:nn #1#2 +{ + \int_compare:nTF { - \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 + \tl_count:n {#1} > 3 + } + { + \group_begin: + \tl_set:Nn \l__spath_shorten_path_tl {#1} + + \tl_set:Nx \l__spath_shorten_fa_tl {\tl_item:Nn \l__spath_shorten_path_tl {4}} + + \tl_clear:N \l__spath_shorten_last_tl + + \tl_if_eq:NNTF \l__spath_shorten_fa_tl \c_spath_curvetoa_tl + { + \int_set:Nn \l__spath_shorten_int {3} + } + { + \int_set:Nn \l__spath_shorten_int {1} + } + + \tl_set_eq:NN \l__spath_shorten_last_tl \c_spath_moveto_tl + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl } + + \prg_replicate:nn { \l__spath_shorten_int } + { + \__spath_tl_put_right_braced:Nx \l__spath_shorten_last_tl {\tl_item:Nn \l__spath_shorten_path_tl {1}} + \__spath_tl_put_right_braced:Nx \l__spath_shorten_last_tl {\tl_item:Nn \l__spath_shorten_path_tl {2}} + \tl_put_right:Nx \l__spath_shorten_last_tl {\tl_item:Nn \l__spath_shorten_path_tl {3}} + + \prg_replicate:nn {3} { - \spath_if_in_p:nn {#1} {length} - && - \spath_if_in_p:nn {#2} {length} + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl } } + } + \__spath_tl_put_right_braced:Nx \l__spath_shorten_last_tl {\tl_item:Nn \l__spath_shorten_path_tl {1}} + \__spath_tl_put_right_braced:Nx \l__spath_shorten_last_tl {\tl_item:Nn \l__spath_shorten_path_tl {2}} + + \fp_set:Nn \l__spath_shorten_x_fp + { + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {5}} + - + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {2}} + } + + \fp_set:Nn \l__spath_shorten_y_fp + { + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {6}} + - + \dim_to_fp:n {\tl_item:Nn \l__spath_shorten_last_tl {3}} + } + + \fp_set:Nn \l__spath_shorten_len_fp + { + sqrt( \l__spath_shorten_x_fp * \l__spath_shorten_x_fp + \l__spath_shorten_y_fp * \l__spath_shorten_y_fp ) + } + + \fp_compare:nTF + { + \l__spath_shorten_len_fp > #2 + } + { + + \fp_set:Nn \l__spath_shorten_len_fp { - \__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}} + #2/ \l__spath_shorten_len_fp } + + \tl_if_eq:NNTF \l__spath_shorten_fa_tl \c_spath_curvetoa_tl { - \spath_remove:nn {#1} {length} + \fp_set:Nn \l__spath_shorten_len_fp + { + \l__spath_shorten_len_fp/3 + } + \spath_split_curve:NNVV + \l__spath_shorten_lasta_tl + \l__spath_shorten_lastb_tl + \l__spath_shorten_last_tl + \l__spath_shorten_len_fp } - \bool_if:nTF { - \spath_if_in_p:nn {#1} {real length} - && - \spath_if_in_p:nn {#2} {real length} + \spath_split_line:NNVV + \l__spath_shorten_lasta_tl + \l__spath_shorten_lastb_tl + \l__spath_shorten_last_tl + \l__spath_shorten_len_fp } + + \prg_replicate:nn {2} { - \__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 }} + \tl_set:Nx \l__spath_shorten_path_tl {\tl_tail:N \l__spath_shorten_path_tl} } + + \tl_put_left:NV \l__spath_shorten_path_tl \l__spath_shorten_lastb_tl + + } + { + + \tl_put_left:NV \l__spath_shorten_path_tl \c_spath_moveto_tl + + \int_compare:nT { - \spath_remove:nn {#1} {real length} + \tl_count:N \l__spath_shorten_path_tl > 3 } - \bool_if:nTF { - \spath_if_in_p:nn {#1} {number of components} - && - \spath_if_in_p:nn {#2} {number of components} + \dim_set:Nn \l__spath_tmpa_dim {\fp_to_dim:n {#2 - \l__spath_shorten_len_fp } } + \spath_shorten_at_start:NV \l__spath_shorten_path_tl \l__spath_tmpa_dim } + } + + \tl_gset_eq:NN \g__spath_output_tl \l__spath_shorten_path_tl + \group_end: + } + { + \tl_gset:Nn \g__spath_output_tl {#1} + } +} +\cs_new_protected_nopar:Npn \spath_shorten_at_start:Nnn #1#2#3 +{ + \__spath_shorten_at_start:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_shorten_at_start:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_shorten_at_start:Nn #1#2 +{ + \spath_shorten_at_start:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_shorten_at_start:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \spath_gshorten_at_start:Nnn #1#2#3 +{ + \__spath_shorten_at_start:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gshorten_at_start:Nnn {NVV, cnn, cVV, NVn} +\cs_new_protected_nopar:Npn \spath_gshorten_at_start:Nn #1#2 +{ + \spath_gshorten_at_start:NVn #1#1{#2} +} +\cs_generate_variant:Nn \spath_gshorten_at_start:Nn {cn, cV, NV} +\cs_new_protected_nopar:Npn \__spath_point_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l__spath_tmpa_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l__spath_tmpa_fp {#2 - floor(#2)} + + \spath_segments_to_seq:Nn \l__spath_tmpa_seq {#1} + + \int_compare:nTF + { + \l__spath_tmpa_int < 1 + } + { + \spath_initialpoint:Nn \l__spath_tmpc_tl {#1} + } + { + \int_compare:nTF { - \__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}} + \l__spath_tmpa_int > \seq_count:N \l__spath_tmpa_seq } { - \spath_remove:nn {#1} {number of components} + \spath_finalpoint:Nn \l__spath_tmpc_tl {#1} } - \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} + + \tl_set:Nx \l__spath_tmpa_tl {\seq_item:Nn \l__spath_tmpa_seq { \l__spath_tmpa_int} } + + \int_compare:nTF + { + \tl_count:N \l__spath_tmpa_tl > 3 } - } - { - \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} + { + \tl_set:Nx \l__spath_tmpb_tl {\tl_item:Nn \l__spath_tmpa_tl {4}} + } + { + \tl_set:Nx \l__spath_tmpb_tl {\tl_item:Nn \l__spath_tmpa_tl {1}} + } + + \tl_clear:N \l__spath_tmpc_tl + + \tl_case:Nn \l__spath_tmpb_tl + { + \c_spath_moveto_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + { + \tl_item:Nn \l__spath_tmpa_tl {2} + } + { + \tl_item:Nn \l__spath_tmpa_tl {3} + } + } + } + + \c_spath_lineto_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp) * ( \tl_item:Nn \l__spath_tmpa_tl {2} ) + + + \l__spath_tmpa_fp * ( \tl_item:Nn \l__spath_tmpa_tl {5} ) + } + } + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp) * ( \tl_item:Nn \l__spath_tmpa_tl {3} ) + + + \l__spath_tmpa_fp * ( \tl_item:Nn \l__spath_tmpa_tl {6} ) + } + } + } + } + + \c_spath_closepath_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp) * ( \tl_item:Nn \l__spath_tmpa_tl {2} ) + + + \l__spath_tmpa_fp * ( \tl_item:Nn \l__spath_tmpa_tl {5} ) + } + } + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp) * ( \tl_item:Nn \l__spath_tmpa_tl {3} ) + + + \l__spath_tmpa_fp * ( \tl_item:Nn \l__spath_tmpa_tl {6} ) + } + } + } + } + + \c_spath_curvetoa_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp)^3 * \tl_item:Nn \l__spath_tmpa_tl {2} + 3 * (1 - \l__spath_tmpa_fp)^2 * (\l__spath_tmpa_fp) * \tl_item:Nn \l__spath_tmpa_tl {5} + 3 * (1 - \l__spath_tmpa_fp) * (\l__spath_tmpa_fp)^2 * \tl_item:Nn \l__spath_tmpa_tl {8} + (\l__spath_tmpa_fp)^3 * \tl_item:Nn \l__spath_tmpa_tl {11} + }} + {\fp_to_dim:n + { + (1 - \l__spath_tmpa_fp)^3 * \tl_item:Nn \l__spath_tmpa_tl {3} + 3 * (1 - \l__spath_tmpa_fp)^2 * (\l__spath_tmpa_fp) * \tl_item:Nn \l__spath_tmpa_tl {6} + 3 * (1 - \l__spath_tmpa_fp) * (\l__spath_tmpa_fp)^2 * \tl_item:Nn \l__spath_tmpa_tl {9} + (\l__spath_tmpa_fp)^3 * \tl_item:Nn \l__spath_tmpa_tl {12} + }} + } + } } } + } + + \tl_gclear:N \g__spath_output_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpc_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_point_at:Nnn #1#2#3 +{ + \__spath_point_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_point_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \spath_gpoint_at:Nnn #1#2#3 +{ + \__spath_point_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gpoint_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \__spath_tangent_at:nn #1#2 +{ + \group_begin: + \int_set:Nn \l__spath_tmpa_int {\fp_to_int:n {floor(#2) + 1}} + \fp_set:Nn \l__spath_tmpa_fp {#2 - floor(#2)} + + \spath_segments_to_seq:Nn \l__spath_tmpa_seq {#1} + + \int_compare:nTF + { + \l__spath_tmpa_int < 1 + } + { + \spath_initialpoint:Nn \l__spath_tmpc_tl {#1} + } + { + \int_compare:nTF { - \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} + \l__spath_tmpa_int > \seq_count:N \l__spath_tmpa_seq } { - \__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_finalpoint:Nn \l__spath_tmpc_tl {#1} } { - \spath_remove:nn {#1} {reverse path} + + \tl_set:Nx \l__spath_tmpa_tl {\seq_item:Nn \l__spath_tmpa_seq { \l__spath_tmpa_int} } + + \int_compare:nTF + { + \tl_count:N \l__spath_tmpa_tl > 3 + } + { + \tl_set:Nx \l__spath_tmpb_tl {\tl_item:Nn \l__spath_tmpa_tl {4}} + } + { + \tl_set:Nx \l__spath_tmpb_tl {\tl_item:Nn \l__spath_tmpa_tl {1}} + } + + \tl_clear:N \l__spath_tmpc_tl + + \tl_case:Nn \l__spath_tmpb_tl + { + \c_spath_moveto_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + { + \tl_item:Nn \l__spath_tmpa_tl {2} + } + { + \tl_item:Nn \l__spath_tmpa_tl {3} + } + } + } + + \c_spath_lineto_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + ( \tl_item:Nn \l__spath_tmpa_tl {5} ) + - + ( \tl_item:Nn \l__spath_tmpa_tl {2} ) + } + } + {\fp_to_dim:n + { + ( \tl_item:Nn \l__spath_tmpa_tl {6} ) + - + ( \tl_item:Nn \l__spath_tmpa_tl {3} ) + } + } + } + } + + \c_spath_closepath_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + ( \tl_item:Nn \l__spath_tmpa_tl {5} ) + - + ( \tl_item:Nn \l__spath_tmpa_tl {2} ) + } + } + {\fp_to_dim:n + { + ( \tl_item:Nn \l__spath_tmpa_tl {6} ) + - + ( \tl_item:Nn \l__spath_tmpa_tl {3} ) + } + } + } + } + + \c_spath_curvetoa_tl + { + \tl_set:Nx \l__spath_tmpc_tl + { + {\fp_to_dim:n + { + 3*(1 - \l__spath_tmpa_fp)^2 * (\tl_item:Nn \l__spath_tmpa_tl {5} - \tl_item:Nn \l__spath_tmpa_tl {2}) + + 6 * (1 - \l__spath_tmpa_fp) * (\l__spath_tmpa_fp) * (\tl_item:Nn \l__spath_tmpa_tl {8} - \tl_item:Nn \l__spath_tmpa_tl {5}) + + 3*(\l__spath_tmpa_fp)^2 * (\tl_item:Nn \l__spath_tmpa_tl {11} - \tl_item:Nn \l__spath_tmpa_tl {8}) + } + } + {\fp_to_dim:n + { + 3*(1 - \l__spath_tmpa_fp)^2 * (\tl_item:Nn \l__spath_tmpa_tl {6} - \tl_item:Nn \l__spath_tmpa_tl {3}) + + 6 * (1 - \l__spath_tmpa_fp) * (\l__spath_tmpa_fp) * (\tl_item:Nn \l__spath_tmpa_tl {9} - \tl_item:Nn \l__spath_tmpa_tl {6}) + + 3*(\l__spath_tmpa_fp)^2 * (\tl_item:Nn \l__spath_tmpa_tl {12} - \tl_item:Nn \l__spath_tmpa_tl {9}) + }} + } + } + } } } + + \tl_gclear:N \g__spath_output_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpc_tl + \group_end: } -\cs_new_nopar:Npn \spath_bake_round:n #1 +\cs_new_protected_nopar:Npn \spath_tangent_at:Nnn #1#2#3 { - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl - \pgf@@processround\l__spath_tmpa_tl\l__spath_tmpb_tl - \spath_put:nnV {#1} {path} \l__spath_tmpb_tl + \__spath_tangent_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_close_path:n #1 +\cs_generate_variant:Nn \spath_tangent_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \spath_gtangent_at:Nnn #1#2#3 { - \spath_get:nnN {#1} {initial point} \l__spath_tmpb_tl - \__spath_get:nnN {#1} {path} \l__spath_tmpa_tl - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_closepath_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:nnT {#1} {reverse path} + \__spath_tangent_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gtangent_at:Nnn {NVn, NVV, NnV} +\cs_new_protected_nopar:Npn \__spath_transformation_at:nn #1#2 +{ + \group_begin: + \tl_clear:N \l__spath_tmpa_tl + \__spath_tangent_at:nn {#1}{#2} + \tl_set_eq:NN \l__spath_tmpb_tl \g__spath_output_tl + \fp_set:Nn \l__spath_tmpa_fp { sqrt( (\tl_item:Nn \l__spath_tmpb_tl {1})^2 + (\tl_item:Nn \l__spath_tmpb_tl {2})^2 ) } + \fp_compare:nTF {\l__spath_tmpa_fp = 0} { - \spath_get:nnN {#1} {final point} \l__spath_tmpb_tl - \__spath_get:nnN {#1} {reverse path} \l__spath_tmpa_tl - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_closepath_tl - \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl - \spath_put:nnV {#1} {reverse path} \l__spath_tmpa_tl + \fp_set:Nn \l__spath_tmpa_fp {1} + \fp_set:Nn \l__spath_tmpb_fp {0} } + { + \fp_set:Nn \l__spath_tmpb_fp { (\tl_item:Nn \l__spath_tmpb_tl {2}) / \l__spath_tmpa_fp } + \fp_set:Nn \l__spath_tmpa_fp { (\tl_item:Nn \l__spath_tmpb_tl {1}) / \l__spath_tmpa_fp } + } + \tl_set:Nx \l__spath_tmpa_tl + { + { \fp_to_decimal:n { \l__spath_tmpa_fp } } + { \fp_to_decimal:n { \l__spath_tmpb_fp } } + { \fp_to_decimal:n {- \l__spath_tmpb_fp } } + { \fp_to_decimal:n { \l__spath_tmpa_fp } } + } + \__spath_point_at:nn {#1}{#2} + \tl_put_right:NV \l__spath_tmpa_tl \g__spath_output_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: } -\cs_new_nopar:Npn \spath_map_component:Nn #1#2 +\cs_new_protected_nopar:Npn \spath_transformation_at:Nnn #1#2#3 { - \int_gincr:N \g__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_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 + \__spath_transformation_at:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_transformation_at:Nnn {NVn, NVV, NnV, NvV} +\cs_new_protected_nopar:Npn \spath_gtransformation_at:Nnn #1#2#3 +{ + \__spath_transformation_at:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_generate_variant:Nn \spath_gtransformation_at:Nnn {NVn, NVV, NnV} +\tl_new:N \l__spath_split_path_a_tl +\tl_new:N \l__spath_split_path_b_tl +\tl_new:N \l__spath_split_path_a_start_tl +\tl_new:N \l__spath_split_path_b_start_tl +\tl_new:N \l__spath_split_path_a_end_tl +\tl_new:N \l__spath_split_path_b_end_tl +\tl_new:N \l__spath_split_path_a_final_tl +\tl_new:N \l__spath_split_path_b_final_tl + +\tl_new:N \l__spath_split_prev_first_tl +\tl_new:N \l__spath_split_prev_second_tl + +\seq_new:N \l__spath_split_first_seq +\seq_new:N \l__spath_split_second_seq + +\int_new:N \l__spath_split_segment_int +\cs_new_protected_nopar:Npn \spath_intersect:NN #1#2 +{ + \pgfintersectionofpaths% + {% + \pgfsetpath #1 + }{% + \pgfsetpath #2 } +} +\tl_new:N \l__spath_intersecta_tl +\tl_new:N \l__spath_intersectb_tl +\cs_new_protected_nopar:Npn \spath_intersect:nn #1#2 +{ + \tl_set:Nn \l__spath_intersecta_tl {#1} + \tl_set:Nn \l__spath_intersectb_tl {#2} + \spath_intersect:NN \l__spath_intersecta_tl \l__spath_intersectb_tl +} +\cs_new_protected_nopar:Npn \__spath_split_at_intersections:nn #1#2 +{ + \group_begin: + + % Clear some token lists and sequences + \tl_clear:N \l__spath_split_path_a_final_tl + \tl_clear:N \l__spath_split_path_b_final_tl + \seq_clear:N \l__spath_split_first_seq + \seq_clear:N \l__spath_split_second_seq + + \pgfintersectionsortbyfirstpath + % Find the intersections of these segments + \tl_set:Nn \l__spath_split_path_a_tl {#1} + \tl_set:Nn \l__spath_split_path_b_tl {#2} + % Remove empty components + + \spath_intersect:NN \l__spath_split_path_a_tl \l__spath_split_path_b_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} { - \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 + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} { - \exp_args:NnV \use:c { __spath_map_ \int_use:N \g__spath_map_int :w } \l__spath_tmpb_tl -\tl_clear:N \l__spath_tmpb_tl + \pgfintersectiongetsolutiontimes{##1}{\l__spath_split_first_tl}{\l__spath_split_second_tl} + \seq_put_left:NV \l__spath_split_first_seq \l__spath_split_first_tl } - \tl_if_single:NTF \l__spath_tmpc_tl + } + + \spath_intersect:NN \l__spath_split_path_b_tl \l__spath_split_path_a_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} { - \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl + \pgfintersectiongetsolutiontimes{##1}{\l__spath_split_first_tl}{\l__spath_split_second_tl} + \seq_put_left:NV \l__spath_split_second_seq \l__spath_split_first_tl + } + } + + \tl_set:Nn \l__spath_split_prev_first_tl {-1} + + \seq_map_inline:Nn \l__spath_split_first_seq + { + \tl_set:Nn \l__spath_split_first_tl {##1} + + \tl_set_eq:NN \l__spath_tmpa_tl \l__spath_split_first_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l__spath_split_first_tl) } + = + \fp_to_int:n {floor( \l__spath_split_prev_first_tl) } } { - \tl_put_right:Nx \l__spath_tmpb_tl {{\l__spath_tmpc_tl}} + \tl_set:Nx \l__spath_split_first_tl + { + \fp_eval:n { + floor( \l__spath_split_first_tl ) + + + ( \l__spath_split_first_tl - floor( \l__spath_split_first_tl) ) + / + ( \l__spath_split_prev_first_tl - floor( \l__spath_split_prev_first_tl) ) + } + } } - \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} + \tl_set_eq:NN \l__spath_split_prev_first_tl \l__spath_tmpa_tl + + \spath_split_at:NNVV \l__spath_split_path_a_start_tl \l__spath_split_path_a_end_tl \l__spath_split_path_a_tl \l__spath_split_first_tl + + \tl_put_left:NV \l__spath_split_path_a_final_tl \l__spath_split_path_a_end_tl + \tl_set_eq:NN \l__spath_split_path_a_tl \l__spath_split_path_a_start_tl + + } + + \tl_set:Nn \l__spath_split_prev_second_tl {-1} + + \seq_map_inline:Nn \l__spath_split_second_seq + { + \tl_set:Nn \l__spath_split_second_tl {##1} + + \tl_set_eq:NN \l__spath_tmpa_tl \l__spath_split_second_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l__spath_split_second_tl) } + = + \fp_to_int:n {floor( \l__spath_split_prev_second_tl) } + } + { + \tl_set:Nx \l__spath_split_second_tl + { + \fp_eval:n { + floor( \l__spath_split_second_tl ) + + + ( \l__spath_split_second_tl - floor( \l__spath_split_second_tl) ) + / + ( \l__spath_split_prev_second_tl - floor( \l__spath_split_prev_second_tl) ) + } + } + } + \tl_set_eq:NN \l__spath_split_prev_second_tl \l__spath_tmpa_tl + + \spath_split_at:NNVV \l__spath_split_path_b_start_tl \l__spath_split_path_b_end_tl \l__spath_split_path_b_tl\l__spath_split_second_tl + + \tl_put_left:NV \l__spath_split_path_b_final_tl \l__spath_split_path_b_end_tl + \tl_set_eq:NN \l__spath_split_path_b_tl \l__spath_split_path_b_start_tl + + } + + \tl_put_left:NV \l__spath_split_path_a_final_tl \l__spath_split_path_a_tl + \tl_put_left:NV \l__spath_split_path_b_final_tl \l__spath_split_path_b_tl + + \tl_if_empty:NT \l__spath_split_path_a_final_tl + { + \tl_set_eq:NN \l__spath_split_path_a_final_tl \l__spath_split_path_a_tl } + \tl_if_empty:NT \l__spath_split_path_b_final_tl + { + \tl_set_eq:NN \l__spath_split_path_b_final_tl \l__spath_split_path_b_tl + } + + \spath_remove_empty_components:N \l__spath_split_path_a_final_tl + \spath_remove_empty_components:N \l__spath_split_path_b_final_tl + + \tl_gclear:N \g__spath_output_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_split_path_a_final_tl + \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_split_path_b_final_tl + \group_end: } -\cs_new_nopar:Npn \spath_map_segment_inline:Nn #1#2 +\cs_new_protected_nopar:Npn \spath_split_at_intersections:NNnn #1#2#3#4 { - \int_gincr:N \g__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_map_int :w } ##1 ##2 {#2} - \spath_map_segment_function:Nc #1 { __spath_map_ \int_use:N \g__spath_map_int :w } + \__spath_split_at_intersections:nn {#3}{#4} + \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_set:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_map_segment_inline:nn #1#2 +\cs_generate_variant:Nn \spath_split_at_intersections:NNnn {NNVV, ccVV, ccvv} +\cs_new_protected_nopar:Npn \spath_split_at_intersections:NN #1#2 { - \int_gincr:N \g__spath_map_int - \cs_gset:cpn { __spath_map_ \int_use:N \g__spath_map_int :w } ##1 ##2 {#2} - \spath_get:nnN {#1} {path} \l__spath_tmpd_tl - \spath_map_segment_function:Nc \l__spath_tmpd_tl { __spath_map_ \int_use:N \g__spath_map_int :w } + \spath_split_at_intersections:NNVV #1#2#1#2 } -\cs_new_nopar:Npn \spath_map_segment_function:nN #1#2 +\cs_generate_variant:Nn \spath_split_at_intersections:NN {cc} +\cs_new_protected_nopar:Npn \spath_gsplit_at_intersections:NNnn #1#2#3#4 { - \spath_get:nnN {#1} {path} \l__spath_tmpd_tl - \spath_map_segment_function:NN \l__spath_tmpd_tl #2 + \__spath_split_at_intersections:nn {#3}{#4} + \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}} + \tl_gset:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}} + \tl_gclear:N \g__spath_output_tl } -\cs_new_nopar:Npn \spath_map_segment_function:NN #1#2 +\cs_generate_variant:Nn \spath_gsplit_at_intersections:NNnn {NNVV, ccVV, ccvv} +\cs_new_protected_nopar:Npn \spath_gsplit_at_intersections: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 + \spath_gsplit_at_intersections:NNVV #1#2#1#2 +} +\cs_generate_variant:Nn \spath_gsplit_at_intersections:NN {cc} +\cs_new_protected_nopar:Npn \__spath_split_at_self_intersections:n #1 +{ + \group_begin: - \bool_until_do:nn { - \tl_if_empty_p:N \l__spath_tmpa_tl + % Copy the path + \tl_set:Nn \l__spath_split_path_b_tl {#1} + + % Open the path + \spath_open:N \l__spath_split_path_b_tl + % Remove empty components + \spath_remove_empty_components:N \l__spath_split_path_b_tl + % Make a copy for later + \tl_set_eq:NN \l__spath_split_path_b_final_tl \l__spath_split_path_b_tl + + % Clear some token lists and sequences + \tl_clear:N \l__spath_split_path_a_tl + \seq_clear:N \l__spath_split_first_seq + \int_zero:N \l__spath_split_segment_int + + \pgfintersectionsortbyfirstpath + + \bool_do_until:nn + { + \int_compare_p:n + { + \tl_count:N \l__spath_split_path_b_tl < 4 + } } { - \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:NnF \l__spath_tmpc_tl + \tl_clear:N \l__spath_split_path_a_tl + \tl_put_right:Nx \l__spath_split_path_a_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_item:Nn \l__spath_split_path_b_tl {1} + {\tl_item:Nn \l__spath_split_path_b_tl {2}} + {\tl_item:Nn \l__spath_split_path_b_tl {3}} + } - \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_set:Nx \l__spath_tmpa_tl { \tl_item:Nn \l__spath_split_path_b_tl {4} } - \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:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + + \int_zero:N \l__spath_tmpa_int + \tl_case:Nn \l__spath_tmpa_tl + { + \c_spath_moveto_tl + { + \tl_clear:N \l__spath_split_path_a_tl + \tl_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + \tl_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + \tl_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + } + \c_spath_lineto_tl + { + \int_set:Nn \l__spath_tmpa_int {1} + } + \c_spath_curvetoa_tl + { + \int_set:Nn \l__spath_tmpa_int {3} } + } - \g__spath_curvetoa_tl + \prg_replicate:nn { \l__spath_tmpa_int } + { + \tl_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + \tl_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_tl} + + \tl_put_right:Nx \l__spath_split_path_a_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 + \tl_item:Nn \l__spath_split_path_b_tl {1} + {\tl_item:Nn \l__spath_split_path_b_tl {2}} + {\tl_item:Nn \l__spath_split_path_b_tl {3}} + } - \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_set:Nx \l__spath_split_path_b_tl {\tl_tail:N \l__spath_split_path_b_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_left:NV \l__spath_split_path_b_tl \c_spath_moveto_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_if_empty:NF \l__spath_split_path_a_tl + { + % Intersect the current segment with the rest of the path + \spath_intersect:NN \l__spath_split_path_a_tl \l__spath_split_path_b_tl + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} + { + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} + { + \pgfintersectiongetsolutiontimes{##1}{\l__spath_split_first_tl}{\l__spath_split_second_tl} + \fp_compare:nT + { + \l__spath_split_first_tl < .99 + } + { + \tl_set:Nx \l__spath_tmpa_tl {\fp_to_decimal:n {\l__spath_split_first_tl + \l__spath_split_segment_int}} + \seq_put_right:NV \l__spath_split_first_seq \l__spath_tmpa_tl + } + } } - \g__spath_closepath_tl + \spath_intersect:NN \l__spath_split_path_b_tl \l__spath_split_path_a_tl + + % If we get intersections + \int_compare:nT {\pgfintersectionsolutions > 0} { - \tl_set_eq:NN \l__spath_tmpb_tl \g__spath_moveto_tl - \tl_put_right:Nx \l__spath_tmpb_tl + % Find the times of the intersections on each path + \int_step_inline:nnnn {1} {1} {\pgfintersectionsolutions} { - {\dim_use:N \l__spath_tmpa_dim} - {\dim_use:N \l__spath_tmpb_dim} + \pgfintersectiongetsolutiontimes{##1}{\l__spath_split_first_tl}{\l__spath_split_second_tl} + \fp_compare:nT + { + \l__spath_split_first_tl > .01 + } + { + \tl_set:Nx \l__spath_tmpa_tl {\fp_to_decimal:n {\l__spath_split_first_tl + \l__spath_split_segment_int + 1}} + \seq_put_right:NV \l__spath_split_first_seq \l__spath_tmpa_tl + } } - \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} + } + % Increment the segment counter + \int_incr:N \l__spath_split_segment_int + } - \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} + % Sort the sequence by reverse order along the path + \seq_sort:Nn \l__spath_split_first_seq + { + \fp_compare:nNnTF { ##1 } < { ##2 } + { \sort_return_swapped: } + { \sort_return_same: } + } - } + % Restore the original copy of the path + \tl_set_eq:NN \l__spath_split_path_b_tl \l__spath_split_path_b_final_tl + + % Clear the token lists + \tl_clear:N \l__spath_split_path_b_start_tl + \tl_clear:N \l__spath_split_path_b_end_tl + \tl_clear:N \l__spath_split_path_b_final_tl + \tl_set:Nn \l__spath_split_prev_first_tl {-1} + + \seq_map_inline:Nn \l__spath_split_first_seq + { + \tl_set:Nn \l__spath_split_first_tl {##1} + \tl_set_eq:NN \l__spath_tmpa_tl \l__spath_split_first_tl + \int_compare:nT + { + \fp_to_int:n {floor( \l__spath_split_first_tl ) } + = + \fp_to_int:n {floor( \l__spath_split_prev_first_tl) } } { + \tl_set:Nx \l__spath_split_first_tl + { + \fp_eval:n { + floor( \l__spath_split_first_tl ) + + + ( \l__spath_split_first_tl - floor( \l__spath_split_first_tl) ) + / + ( \l__spath_split_prev_first_tl - floor( \l__spath_split_prev_first_tl) ) + } + } + } + \tl_set_eq:NN \l__spath_split_prev_first_tl \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} + \spath_split_at:NNVV \l__spath_split_path_b_start_tl \l__spath_split_path_b_end_tl \l__spath_split_path_b_tl \l__spath_split_first_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_put_left:NV \l__spath_split_path_b_final_tl \l__spath_split_path_b_end_tl + \tl_set_eq:NN \l__spath_split_path_b_tl \l__spath_split_path_b_start_tl - } + } - #2 \l__spath_tmpc_tl \l__spath_tmpb_tl - \tl_clear:N \l__spath_tmpb_tl + \tl_put_left:NV \l__spath_split_path_b_final_tl \l__spath_split_path_b_tl + \tl_if_empty:NT \l__spath_split_path_b_final_tl + { + \tl_set_eq:NN \l__spath_split_path_b_final_tl \l__spath_split_path_b_tl } + + \spath_remove_empty_components:N \l__spath_split_path_b_final_tl + + \tl_gclear:N \g__spath_output_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_split_path_b_final_tl + \group_end: } -\cs_generate_variant:Nn \spath_map_segment_function:NN {Nc} -\NewDocumentCommand \MakeSPath { m m } -{ - \spath_clear_new:n {#1} - \spath_put:nno {#1} {path} {#2} -} -\NewDocumentCommand \MakeSPathList { m m } +\cs_new_protected_nopar:Npn \spath_split_at_self_intersections:Nn #1#2 { - \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 - } + \__spath_split_at_self_intersections:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\NewDocumentCommand \CloneSPath { m m } +\cs_generate_variant:Nn \spath_split_at_self_intersections:Nn {NV} +\cs_new_protected_nopar:Npn \spath_split_at_self_intersections:N #1 { - \spath_clone:nn {#1} {#2} + \spath_split_at_self_intersections:NV #1#1 } -\NewDocumentCommand \SPathInfo { m m } +\cs_generate_variant:Nn \spath_split_at_self_intersections:N {c} +\cs_new_protected_nopar:Npn \spath_gsplit_at_self_intersections:Nn #1#2 { - \spath_get:nn {#1} {#2} + \__spath_split_at_self_intersections:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\NewDocumentCommand \SPathPrepare { m } +\cs_generate_variant:Nn \spath_gsplit_at_self_intersections:Nn {NV} +\cs_new_protected_nopar:Npn \spath_gsplit_at_self_intersections:N #1 { - \spath_generate_all:n {#1} + \spath_gsplit_at_self_intersections:NV #1#1 } -\NewDocumentCommand \SPathListPrepare { m } +\cs_generate_variant:Nn \spath_gsplit_at_self_intersections:N {c} +\tl_new:N \l__spath_tmpj_tl +\cs_new_protected_nopar:Npn \__spath_join_component:nn #1#2 { - \tl_map_inline:cn {l__spath_list_#1} + \group_begin: + \spath_components_to_seq:Nn \l__spath_tmpa_seq {#1} + \int_compare:nT + { + #2 == 1 + } + { + \tl_clear:N \l__spath_tmpj_tl + \seq_pop_left:NN \l__spath_tmpa_seq \l__spath_tmpj_tl + + \prg_replicate:nn {3} + { + \tl_set:Nx \l__spath_tmpj_tl {\tl_tail:N \l__spath_tmpj_tl} + } + + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpj_tl + } + \bool_if:nT { - \spath_generate_all:n {##1} + \int_compare_p:n + { + #2 > 1 + } + && + \int_compare_p:n + { + #2 <= \seq_count:N \l__spath_tmpa_seq + } } + { + + \seq_clear:N \l__spath_tmpb_seq + \seq_map_indexed_inline:Nn \l__spath_tmpa_seq + { + \tl_set:Nn \l__spath_tmpj_tl {##2} + \int_compare:nT {##1 = #2} + { + \prg_replicate:nn {3} + { + \tl_set:Nx \l__spath_tmpj_tl {\tl_tail:N \l__spath_tmpj_tl} + } + } + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpj_tl + } + + \seq_set_eq:NN \l__spath_tmpa_seq \l__spath_tmpb_seq + } + + \tl_gset:Nx \g__spath_output_tl {\seq_use:Nn \l__spath_tmpa_seq {} } + \group_end: } -\NewDocumentCommand \SPathInfoInto { m m m } +\cs_new_protected_nopar:Npn \spath_join_component:Nnn #1#2#3 { - \tl_clear_new:N #3 - \spath_get:nnN {#1} {#2} #3 + \__spath_join_component:nn {#2}{#3} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\NewDocumentCommand \SPathShow { m } +\cs_generate_variant:Nn \spath_join_component:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_join_component:Nn #1#2 { - \spath_show:n {#1} + \spath_join_component:NVn #1#1{#2} } -\NewDocumentCommand \SPathTranslate { m m m } +\cs_generate_variant:Nn \spath_join_component:Nn {cn, NV, cV} +\cs_new_protected_nopar:Npn \spath_gjoin_component:Nnn #1#2#3 { - \spath_translate:nnn {#1} {#2} {#3} + \__spath_join_component:nn {#2}{#3} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\NewDocumentCommand \SPathTranslateInto { m m m m } +\cs_generate_variant:Nn \spath_gjoin_component:Nnn {NVn, NVV} +\cs_new_protected_nopar:Npn \spath_gjoin_component:Nn #1#2 { - \spath_clone:nn {#1} {#2} - \spath_translate:nnn {#2} {#3} {#4} + \spath_gjoin_component:NVn #1#1{#2} } -\NewDocumentCommand \SPathScale { m m m } +\cs_generate_variant:Nn \spath_gjoin_component:Nn {cn, NV, cV} +\cs_new_protected_nopar:Npn \__spath_spot_weld_components:n #1 { - \spath_scale:nnn {#1} {#2} {#3} + \group_begin: + \dim_zero:N \l__spath_move_x_dim + \dim_zero:N \l__spath_move_y_dim + + \spath_components_to_seq:Nn \l__spath_tmpa_seq {#1} + \seq_clear:N \l__spath_tmpb_seq + \dim_set:Nn \l__spath_move_x_dim {\tl_item:nn {#1} {2} + 10 pt} + \dim_set:Nn \l__spath_move_y_dim {\tl_item:nn {#1} {3} + 10 pt} + + \int_set:Nn \l__spath_tmpa_int {\seq_count:N \l__spath_tmpa_seq} + + \seq_map_inline:Nn \l__spath_tmpa_seq + { + \tl_set:Nn \l__spath_tmpa_tl {##1} + \bool_if:nT + { + \dim_compare_p:n + { + \dim_abs:n {\l__spath_move_x_dim - \tl_item:Nn \l__spath_tmpa_tl {2} } < 0.01pt + } + && + \dim_compare_p:n + { + \dim_abs:n {\l__spath_move_y_dim - \tl_item:Nn \l__spath_tmpa_tl {3} } < 0.01pt + } + } + { + \prg_replicate:nn {3} + { + \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl} + } + \int_decr:N \l__spath_tmpa_int + } + \tl_reverse:N \l__spath_tmpa_tl + \dim_set:Nn \l__spath_move_x_dim {\tl_item:Nn \l__spath_tmpa_tl {2}} + \dim_set:Nn \l__spath_move_y_dim {\tl_item:Nn \l__spath_tmpa_tl {1}} + \tl_reverse:N \l__spath_tmpa_tl + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpa_tl + } + + \tl_set:Nx \l__spath_tmpa_tl {\seq_use:Nn \l__spath_tmpb_seq {} } + \spath_components_to_seq:NV \l__spath_tmpb_seq \l__spath_tmpa_tl + + \spath_initialpoint:Nn \l__spath_tmpa_tl {#1} + \spath_finalpoint:Nn \l__spath_tmpb_tl {#1} + + \bool_if:nT + { + \dim_compare_p:n + { + \dim_abs:n {\tl_item:Nn \l__spath_tmpa_tl {1} - \tl_item:Nn \l__spath_tmpb_tl {1} } < 0.01pt + } + && + \dim_compare_p:n + { + \dim_abs:n {\tl_item:Nn \l__spath_tmpa_tl {2} - \tl_item:Nn \l__spath_tmpb_tl {2} } < 0.01pt + } + } + { + \int_compare:nTF + { + \seq_count:N \l__spath_tmpb_seq > 1 + } + { + \seq_pop_left:NN \l__spath_tmpb_seq \l__spath_tmpb_tl + + \prg_replicate:nn {3} + { + \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl} + } + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpb_tl + } + { + \tl_set:NV \l__spath_tmpb_tl \c_spath_closepath_tl + \tl_put_right:Nx \l__spath_tmpb_tl + { + { \tl_item:Nn \l__spath_tmpa_tl {1} } + { \tl_item:Nn \l__spath_tmpa_tl {2} } + } + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpb_tl + } + } + + \tl_gset:Nx \g__spath_output_tl {\seq_use:Nn \l__spath_tmpb_seq {}} + \group_end: } -\NewDocumentCommand \SPathScaleInto { m m m m } +\cs_new_protected_nopar:Npn \spath_spot_weld_components:Nn #1#2 { - \spath_clone:nn {#1} {#2} - \spath_scale:nnn {#2} {#3} {#4} + \__spath_spot_weld_components:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\NewDocumentCommand \SPathWeld { m m } +\cs_generate_variant:Nn \spath_spot_weld_components:Nn {NV, cV, cn} +\cs_new_protected_nopar:Npn \spath_spot_weld_components:N #1 { - \spath_weld:nn {#1} {#2} + \spath_spot_weld_components:NV #1#1 } -\NewDocumentCommand \SPathWeldInto { m m m } +\cs_generate_variant:Nn \spath_spot_weld_components:N {c} +\cs_new_protected_nopar:Npn \spath_spot_gweld_components:Nn #1#2 { - \spath_clone:nn {#1} {#2} - \spath_weld:nn {#2} {#3} + \__spath_spot_weld_components:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl } -\tikzset{ - save~spath/.code={ - \tikz@addmode{ - \spath_get_current_path:n {#1} - } - }, - restore~spath/.code={ - \spath_set_current_path:n {#1} - } +\cs_generate_variant:Nn \spath_spot_gweld_components:Nn {NV, cV, cn} +\cs_new_protected_nopar:Npn \spath_spot_gweld_components:N #1 +{ + \spath_spot_gweld_components:NV #1#1 } -\cs_new_nopar:Npn \spath_split_curve:nnNN #1#2#3#4 +\cs_generate_variant:Nn \spath_spot_gweld_components:N {c} +\cs_new_protected_nopar:Npn \__spath_convert_to_svg:n #1 { \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} {2}} - {\tl_item:nn {#2} {3}} + \tl_clear:N \l__spath_tmpa_tl + \tl_put_right:Nn \l__spath_tmpa_tl + { + <?xml~ version="1.0"~ standalone="no"?> + \iow_newline: + <!DOCTYPE~ svg~ PUBLIC~ "-//W3C//DTD SVG 1.1//EN"~ + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> + \iow_newline: + <svg~ xmlns="http://www.w3.org/2000/svg"~ version="1.1"~viewBox=" } - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetoa_tl + + \spath_minbb:Nn \l__spath_tmpb_tl {#1} + \spath_maxbb:Nn \l__spath_tmpc_tl {#1} \tl_put_right:Nx \l__spath_tmpa_tl { - {\fp_to_dim:n + \dim_to_decimal:n { - (1 - #1) * \tl_item:nn {#2} {2} + (#1) * \tl_item:nn {#2} {5} - }} - {\fp_to_dim:n + \tl_item:Nn \l__spath_tmpb_tl {1} - 10pt + } + \exp_not:n {~} + \dim_to_decimal: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 + \tl_item:Nn \l__spath_tmpb_tl {2} - 10pt + } + \exp_not:n {~} + \dim_to_decimal: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 + \tl_item:Nn \l__spath_tmpc_tl {1} + - + \tl_item:Nn \l__spath_tmpb_tl {1} + + 20pt + } + \exp_not:n {~} + \dim_to_decimal: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_item:Nn \l__spath_tmpc_tl {2} + - + \tl_item:Nn \l__spath_tmpb_tl {2} + + 20pt + } } - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curveto_tl - \tl_put_right:Nx \l__spath_tmpa_tl + + \tl_put_right:Nn \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} - }} + "> + \iow_newline: + <path~ d=" } - \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 + \tl_set:Nn \l__spath_tmpc_tl {use:n} + \tl_map_inline:Nn #1 { - {\fp_to_dim:n + \tl_set:Nn \l__spath_tmpb_tl {##1} + \tl_case:NnF \l__spath_tmpb_tl + { + \c_spath_moveto_tl { - (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 + \tl_put_right:Nn \l__spath_tmpa_tl {M~} + \tl_set:Nn \l__spath_tmpc_tl {use:n} + } + \c_spath_lineto_tl + { + \tl_put_right:Nn \l__spath_tmpa_tl {L~} + \tl_set:Nn \l__spath_tmpc_tl {use:n} + } + \c_spath_closepath_tl + { + \tl_put_right:Nn \l__spath_tmpa_tl {Z~} + \tl_set:Nn \l__spath_tmpc_tl {use_none:n} + } + \c_spath_curvetoa_tl + { + \tl_put_right:Nn \l__spath_tmpa_tl {C~} + \tl_set:Nn \l__spath_tmpc_tl {use:n} + } + \c_spath_curvetob_tl { + \tl_set:Nn \l__spath_tmpc_tl {use:n} + } + \c_spath_curveto_tl { + \tl_set:Nn \l__spath_tmpc_tl {use: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:Nx \l__spath_tmpa_tl {\use:c { \l__spath_tmpc_tl } {\dim_to_decimal:n {##1}} ~} + } } - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetoa_tl - \tl_put_right:Nx \l__spath_tmpa_tl + \tl_put_right:Nn \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} - }} + "~ fill="none"~ stroke="black"~ /> + \iow_newline: + </svg> + \iow_newline: } - \tl_put_right:NV \l__spath_tmpa_tl \g__spath_curvetob_tl - \tl_put_right:Nx \l__spath_tmpa_tl + \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl + \group_end: +} +\cs_new_protected_nopar:Npn \spath_convert_to_svg:Nn #1#2 +{ + \__spath_convert_to_svg:n {#2} + \tl_set_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\cs_new_protected_nopar:Npn \spath_gconvert_to_svg:Nn #1#2 +{ + \__spath_convert_to_svg:n {#2} + \tl_gset_eq:NN #1 \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl +} +\iow_new:N \g__spath_stream +\cs_new_protected_nopar:Npn \spath_export_to_svg:nn #1#2 +{ + \spath_convert_path_to_svg:Nn \l__spath_iterp_tl {#2} + \iow_open:Nn \g__spath_stream {#1 .svg} + \iow_now:Nx \g__spath_stream { - {\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_use:N \l__spath_iterp_tl } - \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}} + \iow_close:N \g__spath_stream +} +\cs_new_protected_nopar:Npn \spath_show:n #1 +{ + \int_step_inline:nnnn {1} {3} {\tl_count:n {#1}} + { + \iow_term:x { + \tl_item:Nn \l__spath_tmpa_tl {##1} + {\tl_item:Nn \l__spath_tmpa_tl {##1+1}} + {\tl_item:Nn \l__spath_tmpa_tl {##1+2}} + } } - \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_show:n {V, v} -\cs_generate_variant:Nn \spath_split_curve:nnNN {nVNN, VVNN} +\cs_new_protected_nopar:Npn \spath_get_current_path:N #1 +{ + \pgfsyssoftpath@getcurrentpath #1 +} +\cs_new_protected_nopar:Npn \spath_gget_current_path:N #1 +{ + \pgfsyssoftpath@getcurrentpath #1 + \tl_gset_eq:NN #1 #1 +} +\cs_new_protected_nopar:Npn \spath_protocol_path:n #1 +{ + \spath_minbb:Nn \l__spath_tmpa_tl {#1} + \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl + + \spath_maxbb:Nn \l__spath_tmpa_tl {#1} + \exp_last_unbraced:NV \pgf@protocolsizes\l__spath_tmpa_tl +} +\cs_generate_variant:Nn \spath_protocol_path:n {V} +\cs_new_protected_nopar:Npn \spath_set_current_path:n #1 +{ + \spath_protocol_path:n {#1} + \tl_set:Nn \l__spath_tmpa_tl {#1} + \pgfsyssoftpath@setcurrentpath\l__spath_tmpa_tl +} +\cs_new_protected_nopar:Npn \spath_set_current_path:N #1 +{ + \spath_protocol_path:V #1 + \pgfsyssoftpath@setcurrentpath #1 +} +\cs_generate_variant:Nn \spath_set_current_path:N {c} +\cs_new_protected_nopar:Npn \spath_use_path:nn #1#2 +{ + \spath_set_current_path:n {#1} + \pgfusepath{#2} +} +\cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2 +{ + \path[#1] \pgfextra{ + \spath_set_current_path:n {#2} + \tl_put_right:Nn \tikz@preactions {\def\tikz@actions@path{#2}} + }; +} +\cs_generate_variant:Nn \spath_tikz_path:nn {Vn, VV, nv, Vv, nV} +\cs_new_protected_nopar:Npn \spath_set_tikz_coords:n #1 +{ + \spath_finalpoint:Nn \l__spath_tmpa_tl {#1} + \tl_set:Nx \l__spath_tmpa_tl + { + \exp_not:c {tikz@lastx}=\tl_item:Nn \l__spath_tmpa_tl {1} + \exp_not:c {tikz@lasty}=\tl_item:Nn \l__spath_tmpa_tl {2} + \exp_not:c {tikz@lastxsaved}=\tl_item:Nn \l__spath_tmpa_tl {1} + \exp_not:c {tikz@lastysaved}=\tl_item:Nn \l__spath_tmpa_tl {2} + } + \tl_use:N \l__spath_tmpa_tl +} +\cs_generate_variant:Nn \spath_set_tikz_coords:n {V, v} %% -%% Copyright (C) 2011-2019 by Andrew Stacey <stacey@math.ntnu.no> +%% Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either @@ -1500,13 +3130,16 @@ manipulating PGF soft paths} %% This work consists of the files spath3.dtx %% calligraphy_doc.tex %% knots_doc.tex +%% spath3.tex %% and the derived files spath3.ins, %% spath3_code.pdf, %% spath3.sty, %% tikzlibrarycalligraphy.code.tex %% tikzlibraryknots.code.tex +%% tikzlibraryspath3.code.tex %% calligraphy.pdf %% knots.pdf +%% spath3.pdf %% README %% %% diff --git a/Master/texmf-dist/tex/latex/spath3/tikzlibrarycalligraphy.code.tex b/Master/texmf-dist/tex/latex/spath3/tikzlibrarycalligraphy.code.tex index 9b0e082b144..e987539cb0b 100644 --- a/Master/texmf-dist/tex/latex/spath3/tikzlibrarycalligraphy.code.tex +++ b/Master/texmf-dist/tex/latex/spath3/tikzlibrarycalligraphy.code.tex @@ -4,10 +4,10 @@ %% %% The original source files were: %% -%% spath3.dtx (with options: `calligraphy') +%% spath3_code.dtx (with options: `calligraphy') %% ---------------------------------------------------------------- %% spath3 --- Functions for manipulating PGF soft paths -%% E-mail: stacey@math.ntnu.no +%% E-mail: loopspace@mathforge.org %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- @@ -17,10 +17,24 @@ \tl_new:N \l__cal_tmpa_tl \tl_new:N \l__cal_tmpb_tl +\tl_new:N \l__cal_tmp_path_tl +\tl_new:N \l__cal_tmp_rpath_tl +\tl_new:N \l__cal_tmp_rpathb_tl +\tl_new:N \l__cal_tmp_patha_tl + +\seq_new:N \l__cal_tmpa_seq + \int_new:N \l__cal_tmpa_int \int_new:N \l__cal_tmpb_int -\int_new:N \l__cal_path_component_int -\int_new:N \l__cal_label_int +\int_new:N \g__cal_path_component_int +\int_new:N \g__cal_label_int + +\fp_new:N \l__cal_tmpa_fp +\fp_new:N \l__cal_tmpb_fp +\fp_new:N \l__cal_tmpc_fp +\fp_new:N \l__cal_tmpd_fp +\fp_new:N \l__cal_tmpe_fp + \dim_new:N \l__cal_tmpa_dim \dim_new:N \l__cal_tmpb_dim \dim_new:N \l__cal_tmpc_dim @@ -29,10 +43,12 @@ \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_annotate_bool \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 @@ -40,27 +56,35 @@ \bool_set_true:N \l__cal_taper_end_bool \cs_generate_variant:Nn \tl_put_right:Nn {Nv} + +\msg_new:nnn { calligraphy } { undefined pen } { The~ pen~ "#1"~ is~ not~ defined. } \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}} + \spath_components_to_seq:NV \l__cal_tmpa_seq \l__cal_tmpa_tl + \seq_gclear_new:c {g__cal_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + \seq_gset_eq:cN {g__cal_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} \l__cal_tmpa_seq \pgfusepath{discard}% } }, define~pen/.default={default}, use~pen/.code={ \tikzset{pen~name=#1} - \int_gzero:N \l__cal_path_component_int + \int_gzero:N \g__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}} + \spath_components_to_seq:NV \l__cal_tmpa_seq \l__cal_tmpa_tl + \tl_if_exist:cTF {g__cal_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + { + \cal_path_create:Nc \l__cal_tmpa_seq {g__cal_pen_\pgfkeysvalueof{/tikz/pen~name}_seq} + } + { + \msg_warning:nnx { calligraphy } { undefined pen } { \pgfkeysvalueof{/tikz/pen~name} } + } } }, use~pen/.default={default}, @@ -132,8 +156,8 @@ \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} + \tl_clear_new:c {l__cal_stroke_inline_style_ \int_use:N \g__cal_path_component_int} + \tl_set:cn {l__cal_stroke_inline_style_ \int_use:N \g__cal_path_component_int} {#1} }, annotate/.style={ annotate~if, @@ -151,12 +175,13 @@ } }, annotate~reset/.code={ - \int_gzero:N \l__cal_label_int + \int_gzero:N \g__cal_label_int }, annotation~style/.initial={draw,->}, annotation~shift/.initial={(0,1ex)}, every~annotation~node/.initial={anchor=south~west}, annotation~node~style/.code~2~args={ + \tl_clear_new:c {l__cal_annotation_style_ #1 _tl} \tl_set:cn {l__cal_annotation_style_ #1 _tl}{#2} }, tl~use:N/.code={ @@ -179,7 +204,7 @@ { \pgfkeyssetvalue{\pgfkeyscurrentpath}{#1} } - } + }, } \NewDocumentCommand \pen { O{} } { @@ -195,100 +220,99 @@ { \path[use~ pen,every~ calligraphy/.try,#1] } -\NewDocumentCommand \CalligraphyPathCreate { m m } +\cs_new_protected_nopar:Npn \cal_path_create:NN #1#2 { \int_zero:N \l__cal_tmpa_int - \tl_map_inline:cn {l__spath_list_#1} + \seq_map_inline:Nn #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_compare:nT {\tl_count:n {##1} > 3} { - \int_incr:N \l__cal_tmpb_int - \group_begin: - \pgfsys@beginscope - - \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__cal_tmpa_tl - \spath_translate:nV {calligraphy temp path} \l__cal_tmpa_tl + \int_incr:N \l__cal_tmpa_int + \int_zero:N \l__cal_tmpb_int - \__spath_get:nnN {####1} {length} \l__cal_tmpa_tl + \tl_set:Nn \l__cal_tmp_path_tl {##1} + \spath_open:N \l__cal_tmp_path_tl + \spath_reverse:NV \l__cal_tmp_rpath_tl \l__cal_tmp_path_tl - \int_compare:nTF {\l__cal_tmpa_tl = 1} + \seq_map_inline:Nn #2 { - \cal_at_least_three:n {calligraphy temp path} - - \spath_protocol_path:n {calligraphy temp path} + \int_incr:N \l__cal_tmpb_int + \group_begin: + \pgfsys@beginscope + \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_initialpoint:Nn \l__cal_tmpa_tl {####1} + \tl_set_eq:NN \l__cal_tmp_patha_tl \l__cal_tmp_path_tl + \spath_translate:NV \l__cal_tmp_patha_tl \l__cal_tmpa_tl + + \int_compare:nTF {\tl_count:n {####1} == 3} + { + \cal_at_least_three:N \l__cal_tmp_patha_tl + \spath_protocol_path:V \l__cal_tmp_patha_tl - \__spath_get:nnN {calligraphy temp path} {path} \l__cal_tmpa_tl + \tikz@options + \dim_set:Nn \l__cal_line_width_dim {\pgflinewidth} + \cal_maybe_taper:N \l__cal_tmp_patha_tl + } + { + \spath_weld:Nn \l__cal_tmp_patha_tl {####1} + \spath_weld:NV \l__cal_tmp_patha_tl \l__cal_tmp_rpath_tl + \spath_reverse:Nn \l__cal_tmp_rpathb_tl {####1} + \spath_weld:NV \l__cal_tmp_patha_tl \l__cal_tmp_rpathb_tl + + \tl_clear:N \l__cal_tmpa_tl + \tl_set:Nn \l__cal_tmpa_tl {fill=\pgfkeysvalueof{/tikz/pen~colour},draw=none} + \tl_if_exist:cT {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} + { + \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} + } + \tl_if_exist:cT {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} + { + \tl_put_right:Nn \l__cal_tmpa_tl {,} + \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} + } + \tl_if_exist:cT {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} + { + \tl_put_right:Nn \l__cal_tmpa_tl {,} + \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} + } + \spath_tikz_path:VV \l__cal_tmpa_tl \l__cal_tmp_patha_tl - \tikz@options - \dim_set:Nn \l__cal_line_width_dim {\pgflinewidth} - \cal_maybe_taper:N \l__cal_tmpa_tl + } + \pgfsys@endscope + \group_end: } + + \bool_if:NT \l__cal_annotate_bool { + \seq_get_right:NN #2 \l__cal_tmpa_tl + \spath_finalpoint:NV \l__cal_tmpa_tl \l__cal_tmpa_tl + \spath_translate:NV \l__cal_tmp_path_tl \l__cal_tmpa_tl + \tikz@scan@one@point\pgfutil@firstofone\pgfkeysvalueof{/tikz/annotation~shift} - \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} - - \tl_clear:N \l__cal_tmpa_tl - \tl_set:Nn \l__cal_tmpa_tl {fill=\pgfkeysvalueof{/tikz/pen~colour},draw=none} - \tl_if_exist:cT {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} - { - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_style_ \int_use:N \l__cal_tmpa_int} - } - \tl_if_exist:cT {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} - { - \tl_put_right:Nn \l__cal_tmpa_tl {,} - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_stroke_inline_style_ \int_use:N \l__cal_tmpa_int} - } - \tl_if_exist:cT {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} - { - \tl_put_right:Nn \l__cal_tmpa_tl {,} - \tl_put_right:Nv \l__cal_tmpa_tl {l__cal_nib_style_ \int_use:N \l__cal_tmpb_int} - } - \spath_tikz_path:Vn \l__cal_tmpa_tl {calligraphy temp path} + \spath_translate:Nnn \l__cal_tmp_path_tl {\pgf@x} {\pgf@y} + \pgfkeysgetvalue{/tikz/annotation~style}{\l__cal_tmpa_tl} + \spath_tikz_path:VV \l__cal_tmpa_tl \l__cal_tmp_path_tl + + \spath_finalpoint:NV \l__cal_tmpa_tl \l__cal_tmp_path_tl + + \exp_last_unbraced:NV \pgfqpoint \l__cal_tmpa_tl + \begin{scope}[reset~ cm] + \node[every~annotation~node/.try,tl~use:c = {l__cal_annotation_style_ \int_use:N \l__cal_tmpa_int _tl}] at (\pgf@x,\pgf@y) {\int_use:N \l__cal_tmpa_int}; + \end{scope} } - \pgfsys@endscope - \group_end: - } - \bool_if:NT \l__cal_annotate_bool - { - \spath_clone:nn {##1} {calligraphy temp path} - \tl_set_eq:Nc \l_tmpa_tl {l__spath_list_calligraphy pen #2} - \tl_reverse:N \l_tmpa_tl - \tl_set:Nx \l_tmpa_tl {\tl_head:N \l_tmpa_tl} - \spath_generate_finalpoint:V \l_tmpa_tl - \spath_get:VnN \l_tmpa_tl {final point} \l_tmpa_tl - \spath_translate:nV {calligraphy temp path} \l_tmpa_tl - \tikz@scan@one@point\pgfutil@firstofone\pgfkeysvalueof{/tikz/annotation~shift} - \spath_translate:nnn {calligraphy temp path} {\pgf@x} {\pgf@y} - - \pgfkeysgetvalue{/tikz/annotation~style}{\l_tmpa_tl} - \spath_tikz_path:Vn \l_tmpa_tl {calligraphy temp path} - \spath_get:nnN {calligraphy temp path} {final point} \l_tmpa_tl - \exp_last_unbraced:NV \pgfqpoint \l_tmpa_tl - \begin{scope}[reset~ cm] - \node[every~annotation~node/.try,tl~use:c = {l__cal_annotation_style_ \int_use:N \l__cal_tmpa_int _tl}] at (\pgf@x,\pgf@y) {\int_use:N \l__cal_tmpa_int}; - \end{scope} } } } +\cs_generate_variant:Nn \cal_path_create:NN {Nc} \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 + \int_gincr:N \g__cal_path_component_int \cal_orig_moveto:n {#1} } \cs_new_nopar:Npn \cal_apply_style:N #1 @@ -298,154 +322,32 @@ } } \cs_generate_variant:Nn \cal_apply_style:N {c} -\cs_new_nopar:Npn \cal_at_least_three:n #1 +\cs_new_protected_nopar:Npn \cal_at_least_three:Nn #1#2 { - \spath_get:nnN {#1} {real length} \l__cal_tmpa_tl + \spath_reallength:Nn \l__cal_tmpa_int {#2} \tl_clear:N \l__cal_tmpb_tl - \int_compare:nTF {\l__cal_tmpa_tl = 1} + \tl_set:Nn \l__cal_tmpb_tl {#2} + \int_compare:nTF {\l__cal_tmpa_int = 1} { - \spath_get:nnN {#1} {path} \l__cal_tmpa_tl - \spath_map_segment_inline:Nn \l__cal_tmpa_tl - { - \tl_case:NnF ##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 + \spath_split_at:Nn \l__cal_tmpb_tl {2/3} + \spath_split_at:Nn \l__cal_tmpb_tl {1/2} } { - \int_compare:nT {\l__cal_tmpa_tl = 2} + \int_compare:nT {\l__cal_tmpa_int = 2} { - \spath_get:nnN {#1} {path} \l__cal_tmpa_tl - \spath_map_segment_inline:Nn \l__cal_tmpa_tl - { - \tl_case:NnF ##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 + \spath_split_at:Nn \l__cal_tmpb_tl {1.5} + \spath_split_at:Nn \l__cal_tmpb_tl {.5} } } + \tl_set_eq:NN #1 \l__cal_tmpb_tl } -\cs_new_nopar:Npn \cal_split_line_in_two:NN #1#2 +\cs_generate_variant:Nn \cal_at_least_three:Nn {NV} +\cs_new_protected_nopar:Npn \cal_at_least_three:N #1 { - \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} - } + \cal_at_least_three:NV #1#1 } -\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} - } -} -\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 -} -\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 -} -\cs_new_nopar:Npn \cal_maybe_taper:N #1 +\cs_generate_variant:Nn \cal_at_least_three:N {c} +\cs_new_protected_nopar:Npn \cal_maybe_taper:N #1 { \tl_set_eq:NN \l__cal_tmpa_tl #1 @@ -458,7 +360,7 @@ \tl_case:NnF \l__cal_tmpb_tl { - \g__spath_lineto_tl + \c_spath_lineto_tl { \bool_set_true:N \l__cal_taperable_bool @@ -472,9 +374,9 @@ { \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 + \tl_put_left:NV \l__cal_tmpa_tl \c_spath_moveto_tl } - \g__spath_curvetoa_tl + \c_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}} @@ -487,7 +389,7 @@ { \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 + \tl_put_left:NV \l__cal_tmpa_tl \c_spath_moveto_tl } } { @@ -510,7 +412,7 @@ \tl_case:NnF \l__cal_tmpb_tl { - \g__spath_lineto_tl + \c_spath_lineto_tl { \bool_set_true:N \l__cal_taperable_bool @@ -527,7 +429,7 @@ } \tl_reverse:N \l__cal_tmpa_tl } - \g__spath_curveto_tl + \c_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}} @@ -560,10 +462,10 @@ \pgfusepath{stroke} } -\cs_new_nopar:Npn \__cal_taper_aux: +\cs_new_protected_nopar:Npn \__cal_taper_aux: { \tl_clear:N \l__cal_tmpb_tl - \tl_put_right:NV \l__cal_tmpb_tl \g__spath_moveto_tl + \tl_put_right:NV \l__cal_tmpb_tl \c_spath_moveto_tl \fp_set:Nn \l__cal_tmpa_fp { @@ -603,7 +505,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetoa_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -611,7 +513,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetob_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -619,7 +521,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curveto_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -627,7 +529,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetoa_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -635,7 +537,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetob_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -643,7 +545,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curveto_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -651,7 +553,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetoa_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -659,7 +561,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetob_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -667,7 +569,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curveto_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -675,7 +577,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetoa_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -683,7 +585,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curvetob_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -691,7 +593,7 @@ {\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:NV \l__cal_tmpb_tl \c_spath_curveto_tl \tl_put_right:Nx \l__cal_tmpb_tl { @@ -704,8 +606,14 @@ \pgfusepath{fill} } \tl_set:Nn \l__cal_tmpa_tl {\pgfsyssoftpath@movetotoken{0pt}{0pt}} -\MakeSPathList{calligraphy pen copperplate}{\l__cal_tmpa_tl} -\SPathListPrepare{calligraphy pen copperplate} +\spath_components_to_seq:NV \l__cal_tmpa_seq \l__cal_tmpa_tl +\seq_gclear_new:N \g__cal_pen_copperplate_seq +\seq_gset_eq:NN \g__cal_pen_copperplate_seq \l__cal_tmpa_seq +\DeclareDocumentCommand \CopperplatePath { m } +{ + \spath_components_to_seq:NV \l__cal_tmpa_seq #1 + \cal_path_create:NN \l__cal_tmpa_seq \g__cal_pen_copperplate_seq +} \ExplSyntaxOff \expandafter\ifx\csname pgfdeclaredecoration\endcsname\relax \else @@ -745,9 +653,7 @@ taper }% \pgfsyssoftpath@getcurrentpath\cal@tmp@path - \MakeSPathList{calligraphy path}{\cal@tmp@path}% - \SPathListPrepare{calligraphy path}% - \CalligraphyPathCreate{calligraphy path}{copperplate}% + \CopperplatePath{\cal@tmp@path} } \state{final}{} } @@ -774,9 +680,7 @@ taper }% \pgfsyssoftpath@getcurrentpath\cal@tmp@path - \MakeSPathList{calligraphy path}{\cal@tmp@path}% - \SPathListPrepare{calligraphy path}% - \CalligraphyPathCreate{calligraphy path}{copperplate}% + \CopperplatePath{\cal@tmp@path} } \state{final}{}% } @@ -798,15 +702,13 @@ taper }% \pgfsyssoftpath@getcurrentpath\cal@tmp@path - \MakeSPathList{calligraphy path}{\cal@tmp@path}% - \SPathListPrepare{calligraphy path}% - \CalligraphyPathCreate{calligraphy path}{copperplate}% + \CopperplatePath{\cal@tmp@path} } \state{final}{}% } \fi %% -%% Copyright (C) 2011-2019 by Andrew Stacey <stacey@math.ntnu.no> +%% Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either @@ -821,13 +723,16 @@ %% This work consists of the files spath3.dtx %% calligraphy_doc.tex %% knots_doc.tex +%% spath3.tex %% and the derived files spath3.ins, %% spath3_code.pdf, %% spath3.sty, %% tikzlibrarycalligraphy.code.tex %% tikzlibraryknots.code.tex +%% tikzlibraryspath3.code.tex %% calligraphy.pdf %% knots.pdf +%% spath3.pdf %% README %% %% diff --git a/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex b/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex index 0322a679410..5872a71fdf3 100644 --- a/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex +++ b/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex @@ -4,17 +4,17 @@ %% %% The original source files were: %% -%% spath3.dtx (with options: `knots') +%% spath3_code.dtx (with options: `knots') %% ---------------------------------------------------------------- %% spath3 --- Functions for manipulating PGF soft paths -%% E-mail: stacey@math.ntnu.no +%% E-mail: loopspace@mathforge.org %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- %% %% \RequirePackage{spath3} -\usetikzlibrary{intersections} +\usetikzlibrary{intersections,spath3} \ExplSyntaxOn @@ -22,8 +22,6 @@ \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 @@ -31,16 +29,21 @@ \tl_new:N \l__knot_node_tl \tl_new:N \l__knot_aux_tl \tl_new:N \l__knot_auxa_tl +\tl_new:N \l__knot_prefix_tl + +\seq_new:N \l__knot_segments_seq \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 \g__knot_intersections_int +\int_new:N \g__knot_filaments_int \int_new:N \l__knot_component_start_int +\fp_new:N \l__knot_tmpa_fp +\fp_new:N \l__knot_tmpb_fp + \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_bg_radius_dim \dim_new:N \l__knot_clip_draw_radius_dim @@ -56,10 +59,16 @@ \bool_new:N \l__knot_skip_bool \bool_new:N \l__knot_save_bool -\seq_new:N \l__knot_nodes_seq +\seq_new:N \g__knot_nodes_seq \bool_set_true:N \l__knot_ignore_ends_bool \tikzset{ + spath/prefix/knot/.style={ + spath/set~ prefix=knot strand, + }, + spath/suffix/knot/.style={ + spath/set~ suffix={}, + }, knot/.code={ \tl_if_eq:nnTF {#1} {none} { @@ -218,7 +227,7 @@ \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] + \path[#1,spath/set~ name=knot,spath/save=\int_use:N \l__knot_strands_int] } \NewDocumentEnvironment{knot} { O{} } { @@ -232,7 +241,7 @@ \tikzset{knot~ diagram/.cd,every~ knot~ diagram/.try,#1} \int_zero:N \l__knot_strands_int \tl_clear:N \l__knot_redraws_tl - \seq_gclear:N \l__knot_nodes_seq + \seq_gclear:N \g__knot_nodes_seq } \cs_new_protected_nopar:Npn \knot_render: { @@ -245,25 +254,23 @@ \bool_if:NTF \l__knot_self_intersections_bool { \knot_split_strands: - \int_set_eq:NN \l__knot_tmpa_int \l__knot_filaments_int + \int_set_eq:NN \l__knot_tmpa_int \g__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} } - \int_gzero:N \l__knot_intersections_int - \bool_if:NTF \l__knot_draft_bool + \int_gzero:N \g__knot_intersections_int + \tl_clear:N \l__knot_node_tl + \bool_if:NT \l__knot_draft_bool { \tl_set:Nn \l__knot_node_tl { \exp_not:N \node[coordinate, - pin={[node~ contents={\int_use:N \l__knot_intersections_int},knot~ diagram/draft/crossing~ label, knot~ diagram/draft/crossing~ \int_use:N \l__knot_intersections_int \c_space_tl label/.try] + pin={[node~ contents={\int_use:N \g__knot_intersections_int},knot~ diagram/draft/crossing~ label, knot~ diagram/draft/crossing~ \int_use:N \g__knot_intersections_int \c_space_tl label/.try] }] } } - { - \tl_set:Nn \l__knot_node_tl {\exp_not:N \node[coordinate]} - } \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 @@ -272,7 +279,7 @@ } } \tl_use:N \l__knot_redraws_tl - \seq_use:Nn \l__knot_nodes_seq {} + \seq_use:Nn \g__knot_nodes_seq {} } \endpgfscope } @@ -280,11 +287,11 @@ { \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_bake_round:n {knot strand #1} - \spath_tikz_path:Vn \l_tmpa_tl {knot strand #1} + \spath_bake_round:c {knot strand #1} + \tl_set:Nn \l__knot_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_put_right:Nv \l__knot_tmpa_tl {l__knot_options_strand #1} + \tl_put_right:Nn \l__knot_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try} + \spath_tikz_path:Vv \l__knot_tmpa_tl {knot strand #1} \group_end: \endpgfscope } @@ -293,11 +300,11 @@ { \bool_if:NT \l__knot_draft_bool { - \spath_get:nnN {knot strand #1} {final point} \l__knot_tmpb_tl + \spath_finalpoint:Nv \l__knot_tmpb_tl {knot strand #1} \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 + \spath_initialpoint:Nv \l__knot_tmpb_tl {knot strand #1} \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}; @@ -309,84 +316,86 @@ } { \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 + \spath_segments_to_seq:Nv \l__knot_segments_seq {knot strand #1} + \seq_map_function:NN \l__knot_segments_seq \knot_split_self_intersects:N + \tl_set_eq:cN {knot strand #1} \l__knot_tmpa_tl } } -\cs_new_protected_nopar:Npn \knot_split_self_intersects:NN #1#2 +\cs_new_protected_nopar:Npn \knot_split_self_intersects:N #1 { - \tl_case:NnF #1 + \tl_set:Nx \l__knot_tmpc_tl {\tl_item:nn {#1} {4}} + \tl_case:NnF \l__knot_tmpc_tl { - \g__spath_curvetoa_tl + \c_spath_curvetoa_tl { - \fp_set:Nn \l_tmpa_fp + \fp_set:Nn \l__knot_tmpa_fp { - (\tl_item:Nn #2 {3} - 3 * \tl_item:Nn #2 {6} + 3 * \tl_item:Nn #2 {9} - \tl_item:Nn #2 {12}) + (\tl_item:nn {#1} {3} - 3 * \tl_item:nn {#1} {6} + 3 * \tl_item:nn {#1} {9} - \tl_item:nn {#1} {12}) * - (3 * \tl_item:Nn #2 {8} - 3 * \tl_item:Nn #2 {11}) + (3 * \tl_item:nn {#1} {8} - 3 * \tl_item:nn {#1} {11}) - - (\tl_item:Nn #2 {2} - 3 * \tl_item:Nn #2 {5} + 3 * \tl_item:Nn #2 {8} - \tl_item:Nn #2 {11}) + (\tl_item:nn {#1} {2} - 3 * \tl_item:nn {#1} {5} + 3 * \tl_item:nn {#1} {8} - \tl_item:nn {#1} {11}) * - (3 * \tl_item:Nn #2 {9} - 3 * \tl_item:Nn #2 {12}) + (3 * \tl_item:nn {#1} {9} - 3 * \tl_item:nn {#1} {12}) } - \fp_set:Nn \l_tmpb_fp + \fp_set:Nn \l__knot_tmpb_fp { - (\tl_item:Nn #2 {2} - 3 * \tl_item:Nn #2 {5} + 3 * \tl_item:Nn #2 {8} - \tl_item:Nn #2 {11}) + (\tl_item:nn {#1} {2} - 3 * \tl_item:nn {#1} {5} + 3 * \tl_item:nn {#1} {8} - \tl_item:nn {#1} {11}) * - (3 * \tl_item:Nn #2 {6} - 6 * \tl_item:Nn #2 {9} + 3 * \tl_item:Nn #2 {12}) + (3 * \tl_item:nn {#1} {6} - 6 * \tl_item:nn {#1} {9} + 3 * \tl_item:nn {#1} {12}) - - (\tl_item:Nn #2 {3} - 3 * \tl_item:Nn #2 {6} + 3 * \tl_item:Nn #2 {9} - \tl_item:Nn #2 {12}) + (\tl_item:nn {#1} {3} - 3 * \tl_item:nn {#1} {6} + 3 * \tl_item:nn {#1} {9} - \tl_item:nn {#1} {12}) * - (3 * \tl_item:Nn #2 {5} - 6 * \tl_item:Nn #2 {8} + 3 * \tl_item:Nn #2 {11}) + (3 * \tl_item:nn {#1} {5} - 6 * \tl_item:nn {#1} {8} + 3 * \tl_item:nn {#1} {11}) } \fp_compare:nTF { - \l_tmpb_fp != 0 + \l__knot_tmpb_fp != 0 } { - \fp_set:Nn \l_tmpa_fp {.5 * \l_tmpa_fp / \l_tmpb_fp} + \fp_set:Nn \l__knot_tmpa_fp {.5 * \l__knot_tmpa_fp / \l__knot_tmpb_fp} \fp_compare:nTF { - 0 < \l_tmpa_fp && \l_tmpa_fp < 1 + 0 < \l__knot_tmpa_fp && \l__knot_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 + \spath_split_curve:NNnV \l__knot_tmpc_tl \l__knot_tmpd_tl {#1} \l__knot_tmpa_fp + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpd_tl {\tl_tail:N \l__knot_tmpd_tl} + \tl_set:Nx \l__knot_tmpd_tl {\tl_tail:N \l__knot_tmpd_tl} + \tl_set:Nx \l__knot_tmpd_tl {\tl_tail:N \l__knot_tmpd_tl} + \tl_put_right:NV \l__knot_tmpa_tl \l__knot_tmpc_tl + \tl_put_right:NV \l__knot_tmpa_tl \l__knot_tmpd_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:Nn \l__knot_tmpc_tl {#1} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_put_right:NV \l__knot_tmpa_tl \l__knot_tmpc_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:Nn \l__knot_tmpc_tl {#1} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_put_right:NV \l__knot_tmpa_tl \l__knot_tmpc_tl } } - \g__spath_lineto_tl + \c_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_set:Nn \l__knot_tmpc_tl {#1} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_set:Nx \l__knot_tmpc_tl {\tl_tail:N \l__knot_tmpc_tl} + \tl_put_right:NV \l__knot_tmpa_tl \l__knot_tmpc_tl } } { - \tl_put_right:NV \l__knot_tmpa_tl #2 + \tl_put_right:Nn \l__knot_tmpa_tl {#1} } } \cs_new_protected_nopar:Npn \knot_intersections:nn #1#2 @@ -396,8 +405,8 @@ \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 + \tl_set_eq:Nc \l__knot_tmpc_tl {knot \tl_use:N \l__knot_tmpa_tl} + \tl_set_eq:Nc \l__knot_tmpd_tl {knot \tl_use:N \l__knot_tmpb_tl} \bool_if:nTF { \l__knot_save_bool @@ -411,10 +420,12 @@ \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 } + \knot_save_intersections:VV \l__knot_tmpa_tl \l__knot_tmpb_tl \group_end: } @@ -464,10 +475,10 @@ \bool_set_false:N \l__knot_skip_bool \bool_if:NT \l__knot_self_intersections_bool { - \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 + \tl_set:Nn \l__knot_tmpc_tl {knot previous} + \tl_put_right:NV \l__knot_tmpc_tl \l__knot_tmpa_tl + \tl_set:Nv \l__knot_tmpc_tl \l__knot_tmpc_tl + \tl_if_eq:NNT \l__knot_tmpc_tl \l__knot_tmpb_tl { \knot_test_endpoint:VnT \l__knot_tmpb_tl {final point} { @@ -475,10 +486,10 @@ } } - \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 + \tl_set:Nn \l__knot_tmpc_tl {knot previous} + \tl_put_right:NV \l__knot_tmpc_tl \l__knot_tmpb_tl + \tl_set:Nv \l__knot_tmpc_tl \l__knot_tmpc_tl + \tl_if_eq:NNT \l__knot_tmpc_tl \l__knot_tmpa_tl { \knot_test_endpoint:VnT \l__knot_tmpa_tl {final point} { @@ -508,23 +519,23 @@ \bool_if:NF \l__knot_skip_bool { - \int_gincr:N \l__knot_intersections_int + \int_gincr:N \g__knot_intersections_int \bool_if:nF { \tl_if_exist_p:c {l__knot_ignore_crossing_ \int_use:N - \l__knot_intersections_int} + \g__knot_intersections_int} && ! \tl_if_empty_p:c {l__knot_ignore_crossing_ \int_use:N - \l__knot_intersections_int} + \g__knot_intersections_int} } { \bool_if:nTF { \tl_if_exist_p:c {l__knot_crossing_ \int_use:N - \l__knot_intersections_int} + \g__knot_intersections_int} && ! \tl_if_empty_p:c {l__knot_crossing_ \int_use:N - \l__knot_intersections_int} + \g__knot_intersections_int} } { \tl_set_eq:NN \l__knot_tmpg_tl \l__knot_tmpb_tl @@ -553,9 +564,10 @@ \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_clear_new:c {knot \tl_use:N \l__knot_prefix_tl -1} + \tl_set_eq:cc {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:N \l__knot_tmpg_tl} + \tl_clear_new:c {l__knot_options_ \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 @@ -567,7 +579,7 @@ !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} } { - \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}} + \spath_prepend_no_move:cv {knot \tl_use:N \l__knot_prefix_tl -1} {knot \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}} \bool_if:nT { \l__knot_splits_bool @@ -579,10 +591,9 @@ { \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 + \spath_prepend_no_move:cv {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}}} + \tl_set_eq:Nc \l__knot_tmpa_tl {knot \tl_use:N \l__knot_prefix_tl -1} } } } @@ -595,7 +606,7 @@ !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl} } { - \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}} + \spath_append_no_move:cv {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 @@ -608,7 +619,7 @@ { \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}}} + \spath_append_no_move:cv {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}}} } } @@ -619,13 +630,16 @@ } \pgfscope \group_begin: - \tikzset{knot~ diagram/every~ intersection/.try, every~ intersection/.try, 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 + \tikzset{knot~ diagram/every~ intersection/.try, every~ intersection/.try, knot~ diagram/intersection~ \int_use:N \g__knot_intersections_int/.try} + \knot_draw_crossing:VVV \l__knot_tmpg_tl \l__knot_tmpa_dim \l__knot_tmpb_dim + \coordinate (\l__knot_name_tl \c_space_tl \int_use:N \g__knot_intersections_int) at (\dim_use:N \l__knot_tmpa_dim, \dim_use:N \l__knot_tmpb_dim); \group_end: \endpgfscope } - \seq_gpush:Nx \l__knot_nodes_seq { \l__knot_node_tl (\l__knot_name_tl \c_space_tl \int_use:N \l__knot_intersections_int) at (\dim_use:N \l__knot_tmpa_dim, \dim_use:N \l__knot_tmpb_dim) {};} - + \tl_if_empty:NF \l__knot_node_tl + { + \seq_gpush:Nx \g__knot_nodes_seq { \l__knot_node_tl at (\dim_use:N \l__knot_tmpa_dim, \dim_use:N \l__knot_tmpb_dim) {};} + } } } @@ -649,7 +663,7 @@ } \prg_new_protected_conditional:Npnn \knot_test_endpoint:nn #1#2 {T,F,TF} { - \spath_get:nnN {knot #1} {#2} \l__knot_tmpd_tl + \use:c {spath_#2:Nv} \l__knot_tmpd_tl {knot #1} \knot_test_endpoint:NTF \l__knot_tmpd_tl { \prg_return_true: @@ -662,49 +676,49 @@ \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} -\cs_new_nopar:Npn \knot_draw_crossing:nnn #1#2#3 +\cs_new_protected_nopar:Npn \knot_draw_crossing:nnn #1#2#3 { \group_begin: \pgfscope \path[knot~ diagram/background~ clip] (#2, #3) circle[radius=\l__knot_clip_bg_radius_dim]; - \tl_set:Nn \l_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_set:Nn \l__knot_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:Nv \l__knot_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} + \tl_put_right:Nn \l__knot_tmpa_tl {,knotbg,line~ width= \tl_use:N \l__knot_clip_width_tl * \pgflinewidth} + \spath_tikz_path:Vv \l__knot_tmpa_tl {knot #1} \endpgfscope \pgfscope \path[knot~ diagram/clip] (#2, #3) circle[radius=\l__knot_clip_draw_radius_dim]; - \tl_set:Nn \l_tmpa_tl {knot~ diagram/every~ strand/.try,} + \tl_set:Nn \l__knot_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:Nv \l__knot_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} + \tl_put_right:Nn \l__knot_tmpa_tl {,knot~ diagram/only~ when~ rendering/.try,only~ when~ rendering/.try} + \spath_tikz_path:Vv \l__knot_tmpa_tl {knot #1} \endpgfscope \group_end: } -\cs_generate_variant:Nn \knot_draw_crossing:nnn {nVV} +\cs_generate_variant:Nn \knot_draw_crossing:nnn {nVV, VVV} -\cs_new_nopar:Npn \knot_draw_crossing:nn #1#2 +\cs_new_protected_nopar:Npn \knot_draw_crossing:nn #1#2 { \tikz@scan@one@point\pgfutil@firstofone #2 \relax \knot_draw_crossing:nVV {#1} \pgf@x \pgf@y } \cs_new_protected_nopar:Npn \knot_split_strands: { - \int_gzero:N \l__knot_filaments_int + \int_gzero:N \g__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 + \int_step_function:nnnN {1} {1} {\g__knot_filaments_int} \knot_compute_nexts:n } \cs_new_protected_nopar:Npn \knot_compute_nexts:n #1 { @@ -713,66 +727,70 @@ } \cs_new_protected_nopar:Npn \knot_split_strand:n #1 { - \int_set_eq:NN \l__knot_component_start_int \l__knot_filaments_int + \int_set_eq:NN \l__knot_component_start_int \g__knot_filaments_int \int_incr:N \l__knot_component_start_int \tl_set_eq:Nc \l__knot_tmpa_tl {l__knot_options_strand #1} - \spath_map_segment_function:nN {knot strand #1} \knot_save_filament:NN + \spath_segments_to_seq:Nv \l__knot_segments_seq {knot strand #1} + \seq_map_function:NN \l__knot_segments_seq \knot_save_filament:N } -\cs_new_protected_nopar:Npn \knot_save_filament:NN #1#2 +\cs_new_protected_nopar:Npn \knot_save_filament:N #1 { - \tl_case:NnF #1 + \tl_set:Nx \l__knot_tmpb_tl {\tl_item:nn {#1} {4}} + \tl_case:NnF \l__knot_tmpb_tl { - \g__spath_moveto_tl + \c_spath_moveto_tl { - \int_compare:nT {\l__knot_component_start_int < \l__knot_filaments_int} + \int_compare:nT {\l__knot_component_start_int < \g__knot_filaments_int} { - \int_set_eq:NN \l__knot_component_start_int \l__knot_filaments_int + \int_set_eq:NN \l__knot_component_start_int \g__knot_filaments_int } } - \g__spath_lineto_tl + \c_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_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_tmpa_tl + \int_gincr:N \g__knot_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g__knot_filaments_int} + \tl_set:cn {knot filament \int_use:N \g__knot_filaments_int} {#1} + + \tl_clear_new:c {l__knot_options_filament \int_use:N \g__knot_filaments_int} + \tl_set_eq:cN {l__knot_options_filament \int_use:N \g__knot_filaments_int} \l__knot_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_clear_new:c {knot previous filament \int_use:N \g__knot_filaments_int} + \int_compare:nF {\l__knot_component_start_int == \g__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 \g__knot_filaments_int} {filament \int_eval:n {\g__knot_filaments_int - 1}} } } - \g__spath_curvetoa_tl + \c_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_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_tmpa_tl + \int_gincr:N \g__knot_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g__knot_filaments_int} + \tl_set:cn {knot filament \int_use:N \g__knot_filaments_int} {#1} + \tl_clear_new:c {l__knot_options_filament \int_use:N \g__knot_filaments_int} + \tl_set_eq:cN {l__knot_options_filament \int_use:N \g__knot_filaments_int} \l__knot_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_clear_new:c {knot previous filament \int_use:N \g__knot_filaments_int} + \int_compare:nF {\l__knot_component_start_int == \g__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 \g__knot_filaments_int} {filament \int_eval:n {\g__knot_filaments_int - 1}} } } - \g__spath_closepath_tl + \c_spath_closepath_tl { - \tl_show:N #2 - \int_gincr:N \l__knot_filaments_int - \spath_clear_new:n {knot filament \int_use:N \l__knot_filaments_int} - \tl_clear:N \l_tmpa_tl - \tl_put_right:Nx {\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_put_right:Nx {\tl_item:Nn #2 {5}\tl_item:Nn #2 {6}} - \tl_show:N \l_tmpa_tl - \spath_put:nnV {knot filament \int_use:N \l__knot_filaments_int} {path} \l_tmpa_tl - \tl_set_eq:cN {l__knot_options_filament \int_use:N \l__knot_filaments_int} \l__knot_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} + \int_gincr:N \g__knot_filaments_int + \tl_clear_new:c {knot filament \int_use:N \g__knot_filaments_int} + \tl_clear:N \l__knot_tmpa_tl + \tl_put_right:Nx {\tl_item:nn {#1} {1}\tl_item:nn {#1} {2}\tl_item:nn {#1} {3}} + \tl_put_right:NV \l__knot_tmpa_tl \c_spath_lineto_tl + \tl_put_right:Nx {\tl_item:nn {#1} {5}\tl_item:nn {#1} {6}} + + \tl_set:cV {knot filament \int_use:N \g__knot_filaments_int} \l__knot_tmpa_tl + \tl_set_eq:cN {l__knot_options_filament \int_use:N \g__knot_filaments_int} \l__knot_tmpa_tl + \tl_clear_new:c {knot previous filament \int_use:N \g__knot_filaments_int} + \int_compare:nF {\l__knot_component_start_int == \g__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 \g__knot_filaments_int} {filament \int_eval:n {\g__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} + \tl_set:cx {knot previous filament \int_use:N \l__knot_component_start_int} {filament \int_use:N \g__knot_filaments_int} } } { @@ -990,7 +1008,7 @@ } } %% -%% Copyright (C) 2011-2019 by Andrew Stacey <stacey@math.ntnu.no> +%% Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either @@ -1005,13 +1023,16 @@ %% This work consists of the files spath3.dtx %% calligraphy_doc.tex %% knots_doc.tex +%% spath3.tex %% and the derived files spath3.ins, %% spath3_code.pdf, %% spath3.sty, %% tikzlibrarycalligraphy.code.tex %% tikzlibraryknots.code.tex +%% tikzlibraryspath3.code.tex %% calligraphy.pdf %% knots.pdf +%% spath3.pdf %% README %% %% diff --git a/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex b/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex new file mode 100644 index 00000000000..32d0d9fea08 --- /dev/null +++ b/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex @@ -0,0 +1,595 @@ +%% +%% This is file `tikzlibraryspath3.code.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% spath3_code.dtx (with options: `tikzspath3') +%% ---------------------------------------------------------------- +%% spath3 --- Functions for manipulating PGF soft paths +%% E-mail: loopspace@mathforge.org +%% Released under the LaTeX Project Public License v1.3c or later +%% See http://www.latex-project.org/lppl.txt +%% ---------------------------------------------------------------- +%% +\RequirePackage{spath3} +\RequirePackage{expl3} +\ExplSyntaxOn + +\tl_new:N \l__spath_current_tl +\tl_new:N \l__spath_reverse_tl +\tl_new:N \l__spath_prefix_tl +\tl_new:N \l__spath_suffix_tl +\tl_new:N \g__spath_smuggle_tl +\seq_new:N \g__spath_tmpa_seq +\seq_new:N \g__spath_tmpb_seq +\bool_new:N \l__spath_draft_bool +\tl_set:Nn \l__spath_prefix_tl {tikz@intersect@path@name@} +\tl_set:Nn \l__spath_suffix_tl {} +\tl_new:N \g__spath_tikzfinish_tl +\cs_new_protected_nopar:Npn \spath_at_end_of_path: +{ + \tl_use:N \g__spath_tikzfinish_tl + \tl_gclear:N \g__spath_tikzfinish_tl +} +\tl_put_right:Nn \tikz@finish {\spath_at_end_of_path:} + +\cs_new_protected_nopar:Npn \spath_save_path:Nn #1#2 +{ + \tl_gput_right:Nn \g__spath_tikzfinish_tl + { + \tl_clear_new:N #1 + \tl_set:Nn #1 {#2} + } +} +\cs_generate_variant:Nn \spath_save_path:Nn {cn, NV, cV} + +\cs_new_protected_nopar:Npn \spath_gsave_path:Nn #1#2 +{ + \tl_gput_right:Nn \g__spath_tikzfinish_tl + { + \tl_gclear_new:N #1 + \tl_gset:Nn #1 {#2} + } +} +\cs_generate_variant:Nn \spath_gsave_path:Nn {cn, NV, cV} +\tikzset{ + spath/.is~family, + spath/.cd, + set~ prefix/.store~ in=\l__spath_prefix_tl, + prefix/.is~choice, + prefix/default/.style={ + /tikz/spath/set~ prefix=tikz@intersect@path@name@ + }, + set~ suffix/.store~ in=\l__spath_suffix_tl, + suffix/.is~choice, + suffix/default/.style={ + /tikz/spath/set~ suffix={} + }, + set~ name/.style={ + /tikz/spath/prefix=#1, + /tikz/spath/suffix=#1 + }, + save/.code={ + \tikz@addmode{ + \spath_get_current_path:N \l__spath_tmpa_tl + \spath_bake_round:NV \l__spath_tmpa_tl \l__spath_tmpa_tl + \spath_save_path:cV {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} \l__spath_tmpa_tl + } + }, + clone/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + { + \tl_clear_new:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \tl_set_eq:cc + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + } + }, + clone~ global/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + { + \tl_gclear_new:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \tl_gset_eq:cc + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + } + }, + save~ global/.code={ + \tikz@addmode{ + \spath_get_current_path:N \l__spath_tmpa_tl + \spath_bake_round:NV \l__spath_tmpa_tl \l__spath_tmpa_tl + \spath_gsave_path:cV + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \l__spath_tmpa_tl + } + }, + save~ to~ aux/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_save_to_aux:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + restore/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_set_current_path:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \spath_set_tikz_coords:v + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + show~current~path/.code={ + \tikz@addmode{ + \pgfsyssoftpath@getcurrentpath\l__spath_tmpa_tl + \iow_term:n {---~ current~ soft~ path~ ---} + \spath_show:V \l__spath_tmpa_tl + } + }, + show/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \iow_term:n {---~ soft~ path~ #1~ ---} + \spath_show:v {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + append/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_get_current_path:N \l__spath_current_tl + \spath_weld:Nv + \l__spath_current_tl + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \spath_set_current_path:N \l__spath_current_tl + \spath_set_tikz_coords:V \l__spath_current_tl + } + }, + join~ with/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + { + \spath_append:cv + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + } + } + }, + spot~ weld/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_spot_weld_components:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_reverse:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + append~ reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_reverse:Nv + \l__spath_reverse_tl + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \spath_get_current_path:N \l__spath_current_tl + \spath_weld:NV \l__spath_current_tl \l__spath_reverse_tl + \spath_set_current_path:N \l__spath_current_tl + \spath_set_tikz_coords:V \l__spath_current_tl + } + }, + insert/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_get_current_path:N \l__spath_current_tl + \spath_append:Nv + \l__spath_current_tl + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \spath_set_current_path:N \l__spath_current_tl + \spath_set_tikz_coords:V \l__spath_current_tl + } + }, + insert~ reverse/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_reverse:Nv + \l__spath_reverse_tl + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \spath_get_current_path:N \l__spath_current_tl + \spath_append:NV \l__spath_current_tl \l__spath_reverse_tl + \spath_set_current_path:N \l__spath_current_tl + \spath_set_tikz_coords:V \l__spath_current_tl + } + }, + shorten~ at~ end/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_shorten_at_end:cn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2} + } + }, + shorten~ at~ start/.code~ 2~ args ={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_shorten_at_start:cn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2} + } + }, + shorten~ at~ both~ ends/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_shorten_at_end:cn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2} + \spath_shorten_at_start:cn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2} + } + }, + translate/.code~ n~ args={3}{ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_translate:cnn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{#2}{#3} + } + }, + export~ to~ svg/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_export_to_svg:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + transform/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \group_begin: + \pgftransformreset + \tikzset{#2} + \pgfgettransform \l__spath_tmpa_tl + \tl_gset:Nn \g__spath_smuggle_tl + { + \spath_transform:cnnnnnn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl + \group_end: + \tl_use:N \g__spath_smuggle_tl + } + }, + transform~global/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \group_begin: + \pgftransformreset + \tikzset{#2} + \pgfgettransform \l__spath_tmpa_tl + \tl_gset:Nn \g__spath_smuggle_tl + { + \spath_gtransform:cnnnnnn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl + \group_end: + \tl_use:N \g__spath_smuggle_tl + } + }, + split~ at~ intersections/.code~ n~ args={2}{ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + { + \spath_split_at_intersections:cc + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl} + } + } + }, + split~ at~ self~ intersections/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_split_at_self_intersections:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + get~ components~ of/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \clist_clear_new:N #2 + \spath_components_to_seq:Nv + \l__spath_tmpa_seq + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \seq_map_inline:Nn \l__spath_tmpa_seq + { + \tl_new:c + {\tl_use:N \l__spath_prefix_tl anonymous_\int_use:N \g__spath_anon_int \tl_use:N \l__spath_suffix_tl} + \tl_set:cn + {\tl_use:N \l__spath_prefix_tl anonymous_\int_use:N \g__spath_anon_int \tl_use:N \l__spath_suffix_tl} {##1} + \clist_put_right:Nx #2 {anonymous_\int_use:N \g__spath_anon_int} + \int_gincr:N \g__spath_anon_int + } + } + }, + render~ components/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \group_begin: + \spath_components_to_seq:Nv + \l__spath_tmpa_seq + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \seq_map_indexed_inline:Nn \l__spath_tmpa_seq + { + \spath_tikz_path:nn + { + every~ spath~ component/.try, + spath ~component~ ##1/.try, + spath ~component/.try={##1}, + every~ #1~ component/.try, + #1 ~component~ ##1/.try, + #1 ~component/.try={##1}, + } + { + ##2 + } + } + \group_end: + } + }, + insert~ gaps~ after~ components/.code~ n~ args={3}{ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \group_begin: + \seq_gclear:N \g__spath_tmpa_seq + \seq_gclear:N \g__spath_tmpb_seq + \foreach \l__spath_tmpa_tl in {#3} + { + \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl + \seq_gput_right:Nx \g__spath_tmpb_seq {\int_eval:n { \l__spath_tmpa_tl + 1 }} + } + \spath_components_to_seq:Nv + \l__spath_tmpa_seq + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \seq_clear:N \l__spath_tmpb_seq + \seq_map_indexed_inline:Nn \l__spath_tmpa_seq + { + \tl_set:Nn \l__spath_tmpa_tl {##2} + \seq_if_in:NnT \g__spath_tmpa_seq {##1} + { + \spath_shorten_at_end:Nn \l__spath_tmpa_tl {#2/2} + } + \seq_if_in:NnT \g__spath_tmpb_seq {##1} + { + \spath_shorten_at_start:Nn \l__spath_tmpa_tl {#2/2} + } + \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpa_tl + } + \tl_gset:Nx \g__spath_output_tl {\seq_use:Nn \l__spath_tmpb_seq {} } + \group_end: + \tl_set_eq:cN + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + \g__spath_output_tl + \tl_gclear:N \g__spath_output_tl + } + }, + join~ components/.code~ 2~ args={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \seq_gclear:N \g__spath_tmpa_seq + \foreach \l__spath_tmpa_tl in {#2} + { + \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl + } + \seq_gsort:Nn \g__spath_tmpa_seq + { + \int_compare:nNnTF {##1} > {##2} + { \sort_return_same: } + { \sort_return_swapped: } + } + \seq_map_inline:Nn \g__spath_tmpa_seq + { + \spath_join_component:cn + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{##1} + } + } + }, + remove~ empty~ components/.code={ + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_remove_empty_components:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + }, + draft~ mode/.is~ choice, + draft~ mode/true/.code={ + \bool_set_true:N \l__spath_draft_bool + }, + draft~ mode/false/.code={ + \bool_set_false:N \l__spath_draft_bool + }, + maybe~ spot~ weld/.code={ + \bool_if:NF \l__spath_draft_bool + { + \tl_if_exist:cT {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + { + \spath_spot_weld_components:c + {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} + } + } + }, + transform~ to/.code~ 2~ args={ + \group_begin: + \tl_if_exist:cTF + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + { + \spath_reallength:Nv + \l__spath_tmpa_int + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + + \tl_set:Nx \l__spath_tmpb_tl + {\fp_to_decimal:n {(#2) * (\l__spath_tmpa_int)}} + \spath_transformation_at:NvV \l__spath_tmpc_tl + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpc_tl + } + { + \tl_gset_eq:NN \g__spath_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} } + } + \group_end: + \exp_last_unbraced:NV \pgfsettransformentries \g__spath_smuggle_tl + \tl_gclear:N \g__spath_smuggle_tl + }, + upright~ transform~ to/.code~ 2~ args={ + \group_begin: + \tl_if_exist:cTF + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + { + \spath_reallength:Nv + \l__spath_tmpa_int + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + + \tl_set:Nx \l__spath_tmpb_tl + {\fp_to_decimal:n {(#2) * (\l__spath_tmpa_int)}} + \spath_transformation_at:NvV \l__spath_tmpc_tl + { + \tl_use:N \l__spath_prefix_tl + #1 + \tl_use:N \l__spath_suffix_tl + } + \l__spath_tmpb_tl + \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpc_tl + } + { + \tl_gset_eq:NN \g__spath_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} } + } + \fp_compare:nT { \tl_item:Nn \g__spath_smuggle_tl {4} < 0} + { + \tl_gset:Nx \g__spath_smuggle_tl + { + { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {1})} } + { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {2})} } + { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {3})} } + { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {4})} } + { \tl_item:Nn \g__spath_smuggle_tl {5} } + { \tl_item:Nn \g__spath_smuggle_tl {6} } + } + } + \group_end: + \exp_last_unbraced:NV \pgfsettransformentries \g__spath_smuggle_tl + \tl_gclear:N \g__spath_smuggle_tl + }, + knot/.style~ n~ args={3}{ + spath/.cd, + split~ at~ self~ intersections=#1, + insert~ gaps~ after~ components={#1}{#2}{#3}, + maybe~ spot~ weld=#1, + render~ components=#1 + }, +} +\tikzdeclarecoordinatesystem{spath}{% + \group_begin: + \tl_set:Nn \l__spath_tmpa_tl {#1} + \tl_trim_spaces:N \l__spath_tmpa_tl + + \seq_set_split:NnV \l__spath_tmpa_seq {~} \l__spath_tmpa_tl + \seq_pop_right:NN \l__spath_tmpa_seq \l__spath_tmpb_tl + + \tl_set:Nx \l__spath_tmpa_tl { \seq_use:Nn \l__spath_tmpa_seq {~} } + \tl_if_exist:cTF + { + \tl_use:N \l__spath_prefix_tl + \tl_use:N \l__spath_tmpa_tl + \tl_use:N \l__spath_suffix_tl + } + { + + \tl_set_eq:Nc + \l__spath_tmpa_tl + { + \tl_use:N \l__spath_prefix_tl + \tl_use:N \l__spath_tmpa_tl + \tl_use:N \l__spath_suffix_tl + } + + \tl_if_empty:NTF \l__spath_tmpa_tl + { + \tl_gset_eq:NN \g__spath_smuggle_tl \pgfpointorigin + } + { + \spath_reallength:NV \l__spath_tmpa_int \l__spath_tmpa_tl + \tl_set:Nx \l__spath_tmpb_tl + {\fp_to_decimal:n {(\l__spath_tmpb_tl) * (\l__spath_tmpa_int)}} + \spath_point_at:NVV \l__spath_tmpc_tl \l__spath_tmpa_tl \l__spath_tmpb_tl + + \tl_clear:N \l__spath_tmpd_tl + \tl_put_right:Nn \l__spath_tmpd_tl {\pgf@x=} + \tl_put_right:Nx \l__spath_tmpd_tl {\tl_item:Nn \l__spath_tmpc_tl {1}} + \tl_put_right:Nn \l__spath_tmpd_tl {\relax} + \tl_put_right:Nn \l__spath_tmpd_tl {\pgf@y=} + \tl_put_right:Nx \l__spath_tmpd_tl {\tl_item:Nn \l__spath_tmpc_tl {2}} + \tl_put_right:Nn \l__spath_tmpd_tl {\relax} + \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpd_tl + } + } + { + \tl_gset_eq:NN \g__spath_smuggle_tl \pgfpointorigin + } + \group_end: + \tl_use:N \g__spath_smuggle_tl +} + +\ExplSyntaxOff +%% +%% Copyright (C) 2011-2019 by Andrew Stacey <loopspace@mathforge.org> +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License (LPPL), either +%% version 1.3c of this license or (at your option) any later +%% version. The latest version of this license is in the file: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This work is "maintained" (as per LPPL maintenance status) by +%% Andrew Stacey. +%% +%% This work consists of the files spath3.dtx +%% calligraphy_doc.tex +%% knots_doc.tex +%% spath3.tex +%% and the derived files spath3.ins, +%% spath3_code.pdf, +%% spath3.sty, +%% tikzlibrarycalligraphy.code.tex +%% tikzlibraryknots.code.tex +%% tikzlibraryspath3.code.tex +%% calligraphy.pdf +%% knots.pdf +%% spath3.pdf +%% README +%% +%% +%% End of file `tikzlibraryspath3.code.tex'. |