texlive[57842] Master/texmf-dist: spath3 (22feb21)

commits+karl at tug.org commits+karl at tug.org
Mon Feb 22 22:52:11 CET 2021


Revision: 57842
          http://tug.org/svn/texlive?view=revision&revision=57842
Author:   karl
Date:     2021-02-22 22:52:11 +0100 (Mon, 22 Feb 2021)
Log Message:
-----------
spath3 (22feb21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/spath3/calligraphy.pdf
    trunk/Master/texmf-dist/doc/latex/spath3/knots.pdf
    trunk/Master/texmf-dist/doc/latex/spath3/spath3.pdf
    trunk/Master/texmf-dist/doc/latex/spath3/spath3.tex
    trunk/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf
    trunk/Master/texmf-dist/source/latex/spath3/spath3_code.dtx
    trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty
    trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex

Modified: trunk/Master/texmf-dist/doc/latex/spath3/calligraphy.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/spath3/knots.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/spath3/spath3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/spath3/spath3.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/spath3/spath3.tex	2021-02-22 14:22:20 UTC (rev 57841)
+++ trunk/Master/texmf-dist/doc/latex/spath3/spath3.tex	2021-02-22 21:52:11 UTC (rev 57842)
@@ -56,6 +56,8 @@
 
   \maketitle
 
+\tableofcontents
+
   \section{Introduction}
 
   The \texttt{spath3} package was originally designed as a low-level package for manipulating the \emph{soft paths} defined by PGF/TikZ.
@@ -124,61 +126,63 @@
 In the second, the clone is global (the original need not be).
 \end{function}
 
-\begin{function}{restore, restore reverse}
+\begin{function}{use}
 \begin{syntax}
-|restore=|\meta{name}
-|restore reverse=|\meta{name}
+|use=|\meta{name}
+|use=|\marg{name, options}
 \end{syntax}
 
-Restores a previously saved soft path to the current path.
-The \Verb+reverse+ version reverses the soft path first.
-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.
+This uses a previously saved soft path at the current juncture in the path declaration.
+If before the path has begun, it is the initial part of the new path.
+If during the path construction then it is stuck in at the current place.
+Note that any keys that affect the soft path directly should be applied \emph{before} this one.
 
+The path can be modified first by using the second form -- note that as far as the \Verb+use+ key is concerned, the whole thing is a single argument.
+The options is a comma separated list and can include:
+%
+\begin{itemize}
+\item |reverse| reverses the inserted path first.
+\item |weld|, |no weld| determines whether to weld the inserted path to the current path.
+Welding means that the |move to| at the start of the inserted path is removed.
+Note that this doesn't \emph{move} the inserted path so this will usually modify the first segment of the inserted path, possibly in unexpected ways.
+\item |move|, |no move| determines whether the inserted path is translated so that it starts where the current path ends.
+\item |transform=|\marg{transformations} applies the specified transformations to the inserted path.
+See the |transform| key in Section~\ref{sec:transform}
+\item Any other key is taken as the name of the path (so it doesn't have to be specified first) with the last one winning.
+\end{itemize}
+
 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 up various internals of TikZ correctly, but there may be some things I've overlooked or not accounted for particularly with regard to existing transformations; if you spot anything working oddly then please report it to me.
 
-Restoring a path also sets things right for positioning nodes along the path.
+In particular, restoring a path should sets things right for positioning nodes along the path.
 Using the \Verb+pos=D+ key on a node positions that node at a particular point on the path.
 Exactly how the parameter is interpreted is the same as for the \Verb+spath+ coordinate system described in Section~\ref{sec:coordinates}.
 \end{function}
 
 \begin{function}{
+  restore,
+  restore reverse
+  insert,
+  insert reverse,
   append,
   append reverse,
   append no move,
   append reverse no move
 }
-\begin{syntax}
-|append=|\meta{name}
-|append reverse=|\meta{name}
-|append no move=|\meta{name}
-|append reverse no move=|\meta{name}
-\end{syntax}
 
-This inserts a soft path, or its reverse, 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.
+These are all aliases to various versions of \Verb+use+ (they originally existed as separate code before I united them all as variants of \Verb+use+).
+The equivalences are:
 
-The path is \emph{welded} on to the current path, meaning that the intervening \Verb+move+ is removed.
-This is particularly useful for creating filled regions.
-The first two versions translate the path so that it starts at the last point on the existing path, the second two versions don't do this translation (the intention being that in such a case the translation is omitted because it is \emph{unnecessary} rather than simply not wanted because the effect of removing the intervening move will adjust the initial segment of the appended path otherwise).
-
-As with restoring a path, the last point and node positioning machinery is established.
-The positioning is relative to the appended part of the path, not the full path.
+\begin{itemize}
+\item |restore| and |insert| are aliases for |use|.
+\item |append| sets the |move| and |weld| keys.
+\item |append no move| just sets the |weld| key.
+\item |reverse| sets the |reverse| key.
+\end{itemize}
 \end{function}
 
-\begin{function}{insert, insert reverse}
-\begin{syntax}
-|insert=|\meta{name}
-|insert reverse=|\meta{name}
-\end{syntax}
-
-Like \Verb+append+ except that it doesn't remove the intervening \Verb+move+ and doesn't translate the inserted path.
-The \Verb+reverse+ version reverses the path first.
-\end{function}
-
 \begin{function}{to}
 \begin{syntax}
 |to=|\marg{name}
@@ -191,6 +195,7 @@
 
 
 \subsection{Transformation Routines}
+\label{sec:transform}
 
 The following keys all apply some sort of transformation to the soft path.
 They do not render the path, but simply adjust it.
@@ -236,41 +241,7 @@
 As with the \Verb+to+ path construction and the \Verb+splice+ method, this won't work if the path ends very close to where it starts.
 \end{function}
 
-\begin{function}{splice, splice global}
-\begin{syntax}
-|splice=|\marg{initial path}\marg{splice path}\marg{final path}
-|splice globally=|\marg{initial path}\marg{splice path}\marg{final path}
-\end{syntax}
 
-This splices the middle path into the gap between the initial and final paths.
-The middle path is transformed to fit (don't try this with a path whose starting and ending points are close together) and the paths are joined so that the last component of the initial path and the first component of the splice path become a single component, and similarly at the other end.
-\end{function}
-
-\begin{function}{join components with, join components globally with}
-\begin{syntax}
-|join components with=|\marg{path}\marg{splice path}
-|join components globally with=|\marg{path}\marg{splice path}
-\end{syntax}
-
-This inserts the |splice path| in the gaps between components of |path|.
-A \emph{spot weld} is performed first to join any components where the end of one is the start of the next.
-The result is a single component path.
-This does \emph{not} close the resulting path, for that see the key |close with|.
-\end{function}
-
-\begin{function}{close, close globally, close with, close globally with}
-\begin{syntax}
-|close=|\marg{path}
-|close globally=|\marg{path}
-|close with=|\marg{path}\marg{splice path}
-|close globally with=|\marg{path}\marg{splice path}
-\end{syntax}
-
-These all close the last component of the given path.
-The first two will insert a line segment if the initial and final points of the component are not sufficiently close.
-The latter two allow you to specify another path to insert.
-\end{function}
-
 \subsection{Intersection Routines}
 
 To use these features you need to use the \texttt{intersections} library.
@@ -317,6 +288,20 @@
 This inserts breaks into a pair of paths at their mutual intersections.
 \end{function}
 
+\begin{function}{
+  replace lines,
+  replace lines globally
+}
+\begin{syntax}
+|replace lines=|\meta{path}
+|replace lines globally=|\meta{path}
+\end{syntax}
+
+The PGF intersection routines have difficulties with parallel, or near parallel, lines.
+One way to counter this is to replace all line segments by ``curves''.
+This is done so that the parametrisation of the curve matches that of the line segment that it is replacing.
+\end{function}
+
 \subsection{Working with Components}
 
 \begin{function}{
@@ -335,7 +320,7 @@
 
 The macro consists of a comma separated list of names of the components (the actual names used are of the form \Verb+anonymous_N+).
 To access an individual component, use the command \Verb+\getComponentOf+.
-This can be used directly in place of a path name in any other key, such as \Verb+restore+, (it is just the \LaTeX3 command \Verb+\clist_item:Nn+).
+This can be used directly in place of a path name in any other key, such as \Verb+use+, (it is just the \LaTeX3 command \Verb+\clist_item:Nn+).
 
 Note that these are \emph{copies} of the components of the original path.
 Changing a component doesn't update the original path.
@@ -365,11 +350,14 @@
 }
 \begin{syntax}
 |insert gaps after components=|\marg{path}\marg{gap}\marg{components}
+|insert gaps after components=|\marg{path}\marg{gap}
 |insert gaps globally after components=|\marg{path}\marg{gap}\marg{components}
+|insert gaps globally after components=|\marg{path}\marg{gap}
 \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| can be used.
+If the list of components is not given the gaps are inserted between all components.
 \end{function}
 
 \begin{function}{
@@ -386,6 +374,31 @@
 If the component is the first one then it is joined to the last component.
 \end{function}
 
+\begin{function}{join components with, join components globally with, join components upright with, join components globally upright with}
+\begin{syntax}
+|join components with=|\marg{path}\marg{splice path}
+|join components with=|\marg{path}\marg{splice path}\marg{list}
+|join components upright with=|\marg{path}\marg{splice path}
+|join components upright with=|\marg{path}\marg{splice path}\marg{list}
+|join components globally with=|\marg{path}\marg{splice path}
+|join components globally with=|\marg{path}\marg{splice path}\marg{list}
+|join components globally upright with=|\marg{path}\marg{splice path}
+|join components globally upright with=|\marg{path}\marg{splice path}\marg{list}
+\end{syntax}
+
+This inserts the |splice path| in the gaps between components of |path| specified by a comma separated list.
+The splice is inserted between each specified component and the next one.
+If the \marg{list} is not given (or is empty) then the splice is inserted between every component except that a \emph{spot weld} is performed first to join any components where the end of one is the start of the next.
+The spot weld is only performed if the list of components is empty.
+
+This does \emph{not} close the resulting path, even if the last component is specified in the list, for that see the key |close with|.
+
+Note that because there is an optional third argument to this key, the second argument must always be enclosed in braces unless it is a single token.
+
+The |upright| versions do a little test to see if the gap is oriented upside-down and if so then they insert the reflection of the splice path.
+\end{function}
+
+
 \begin{function}{
   spot weld,
   spot weld globally
@@ -423,6 +436,31 @@
 As with other list routines, the list is parsed via |foreach| first.
 \end{function}
 
+
+\begin{function}{close, close globally, close with, close globally with}
+\begin{syntax}
+|close=|\marg{path}
+|close globally=|\marg{path}
+|close with=|\marg{path}\marg{splice path}
+|close globally with=|\marg{path}\marg{splice path}
+\end{syntax}
+
+These all close the last component of the given path.
+The first two will insert a line segment if the initial and final points of the component are not sufficiently close.
+The latter two allow you to specify another path to insert.
+\end{function}
+
+\begin{function}{splice, splice global}
+\begin{syntax}
+|splice=|\marg{initial path}\marg{splice path}\marg{final path}
+|splice globally=|\marg{initial path}\marg{splice path}\marg{final path}
+\end{syntax}
+
+This splices the middle path into the gap between the initial and final paths.
+The middle path is transformed to fit (don't try this with a path whose starting and ending points are close together) and the paths are joined so that the last component of the initial path and the first component of the splice path become a single component, and similarly at the other end.
+\end{function}
+
+
 \subsection{Shortening Paths}
 
 \begin{function}{
@@ -473,8 +511,8 @@
 \subsection{Knots}
 
 \begin{function}{
+  knot,
   global knot,
-  knot,
   draft mode
 }
 \begin{syntax}
@@ -544,7 +582,7 @@
 \section{Examples}
 
 \begin{enumerate}
-\item Saving, restoring, inserting, and appending.
+\item Saving and re-using.
 
 \begin{example}
 \begin{tikzpicture}
@@ -554,10 +592,10 @@
   \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[blue, spath/transform={rpath}{shift={(2,2)}}, spath/use=rpath] node[right] {transform};
+\draw[orange] (3,0) [spath/use={rpath, move}] node[right] {moving};
 \draw[red] (3,-1) -- +(0,2) [spath/append=rpath] node[above] {append};
-\draw[spath/restore=rpath] node[right] {restore};
+\draw[spath/use=rpath] node[right] {use};
 \end{tikzpicture}
 \end{example}
 
@@ -570,8 +608,8 @@
   green,
   draw=black,
   ultra thick,
-  spath/restore=apath
-] -- ++(0,-4) [spath/append reverse=apath] -- cycle;
+  spath/use=apath
+] -- ++(0,-4) [spath/use={apath, reverse, move, weld}] -- cycle;
 \end{tikzpicture}
 \end{example}
 
@@ -583,7 +621,7 @@
 \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}];
+  spath/use={tpath}];
 \end{tikzpicture}
 \end{example}
 
@@ -615,7 +653,7 @@
 (7,1) circle[radius=3pt]
 ;
 
-\draw[spath/restore=a];
+\draw[spath/use=a];
 \end{tikzpicture}
 \end{example}
 
@@ -653,9 +691,9 @@
   shorten at end={apath}{7pt},
   shorten at start={apath}{9pt},
   translate={apath}{0pt}{1pt},
-  restore=apath,
+  use=apath,
 ];
-\draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt];
+\draw (0,0) circle[radius=9pt] [spath/use=apath] circle[radius=7pt];
 \end{tikzpicture}
 \end{example}
 
@@ -670,9 +708,9 @@
   shorten at end={apath}{7pt},
   shorten at start={apath}{9pt},
   translate={apath}{0pt}{1pt},
-  restore=apath,
+  use=apath,
 ];
-\draw (0,0) circle[radius=9pt] [spath/insert=apath] circle[radius=7pt];
+\draw (0,0) circle[radius=9pt] [spath/use=apath] circle[radius=7pt];
 \end{tikzpicture}
 \end{example}
 
@@ -699,7 +737,7 @@
     path \k/.try,
     spath/.cd,
     translate=\cpt{0pt}{\k pt},
-    restore=\cpt,
+    use=\cpt,
   ] +(0,3pt) -- +(0,-3pt);
   \node[text=red] at (spath cs:{\cpt} .5) {\(\k\)};
 }
@@ -734,12 +772,12 @@
 }
 
 \foreach[count=\k] \cpt in \pathAcomponents {
-  \draw[spath/restore=\cpt,-Circle];
+  \draw[spath/use=\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];
+  \draw[spath/use=\cpt,-Circle];
   \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)};
 }
 \end{tikzpicture}
@@ -766,12 +804,12 @@
 \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];
+  \draw[blue, line width=2pt,spath/use=\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];
+  \draw[green, line width=2pt,spath/use=\cpt];
   \node[fill=green!50, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .3) {\(\k\)};
 }
 \end{tikzpicture}
@@ -807,7 +845,7 @@
 }
 
 \foreach[count=\k] \cpt in \pathcomponents {
-  \draw[spath/restore=\cpt,-|];
+  \draw[spath/use=\cpt,-|];
   \node[fill=white, fill opacity=.5, circle, text opacity=1] at (spath cs:{\cpt} .5) {\(\k\)};
 }
 \end{tikzpicture}
@@ -826,7 +864,7 @@
 }
 
 \foreach[count=\k] \cpt in \pathcomponents {
-  \draw[blue, line width=2pt,spath/restore=\cpt];
+  \draw[blue, line width=2pt,spath/use=\cpt];
 }
 \end{tikzpicture}
 \end{example}
@@ -843,5 +881,65 @@
 \tikzset{spath/knot={trefoil}{8pt}{1,3,5}}
 \end{tikzpicture}
 \end{example}
+
+\item Here's how to mark intersections of paths with ``bridges''.
+\begin{example}
+\begin{tikzpicture}
+\coordinate (a) at (-1,0.5);
+\coordinate (b) at (8,0.5);
+\coordinate (c) at (3,-0.5);
+\path[spath/save=sine]
+(-1.57,-1)
+cos ++(1.57,1)
+sin ++(1.57,1)
+cos ++(1.57,-1)
+sin ++(1.57,-1)
+cos ++(1.57,1)
+sin ++(1.57,1);
+\path[spath/save=over] (a) -- (c) |- (b);
+
+\path[spath/save=arc] (0,0) arc[radius=1cm, start angle=180, delta angle=-180];
+
+\tikzset{
+  spath/split at intersections with={over}{sine},
+  spath/insert gaps after components={over}{8pt},
+  spath/join components upright with={over}{arc},
+  spath/split at intersections with={sine}{over},
+  spath/insert gaps after components={sine}{4pt},
+}
+
+\draw[spath/use=sine];
+\draw[spath/use=over];
+\end{tikzpicture}
+\end{example}
+
+\item If there are lots of paths like the previous example, here's a convenient style to put them together.
+\begin{example}
+\tikzset{
+  bridging path/.initial=arc,
+  bridging span/.initial=8pt,
+  bridging gap/.initial=4pt,
+  bridge/.style 2 args={
+    spath/split at intersections with={#1}{#2},
+    spath/insert gaps after components={#1}{\pgfkeysvalueof{/tikz/bridging span}},
+    spath/join components upright with={#1}{\pgfkeysvalueof{/tikz/bridging path}},
+    spath/split at intersections with={#2}{#1},
+    spath/insert gaps after components={#2}{\pgfkeysvalueof{/tikz/bridging gap}},
+  }
+}
+
+% If used in the preamble, this needs surrounding in \AtBeginDocument
+%\AtBeginDocument{
+\tikz[overlay] \path[spath/save=arc] (0,0) arc[radius=1cm, start angle=180, delta angle=-180];
+%}
+\begin{tikzpicture}
+\path[spath/save=over] (0,0) -| ++(1,1) -| ++(-1,1) -| ++(1,1) -| ++(-1,1);
+\path[spath/save=under] (.5,-.5) -- ++(0,4);
+\tikzset{bridge={over}{under}}
+\draw[spath/use=over];
+\draw[spath/use=under];
+\end{tikzpicture}
+\end{example}
+
 \end{enumerate}
   \end{document}

Modified: trunk/Master/texmf-dist/doc/latex/spath3/spath3_code.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/spath3/spath3_code.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/spath3/spath3_code.dtx	2021-02-22 14:22:20 UTC (rev 57841)
+++ trunk/Master/texmf-dist/source/latex/spath3/spath3_code.dtx	2021-02-22 21:52:11 UTC (rev 57842)
@@ -143,7 +143,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{8404}
+% \CheckSum{8929}
 %
 % \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
@@ -168,6 +168,7 @@
 % \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.}
 % \changes{2.2}{2021/02/05}{Bugfixes and improvements, mainly with regard to the intersection and splitting routines.}
+% \changes{2.4}{2021/02/21}{Rejigged how the routines for using paths were implemented, added some more routines for joining paths.}
 %
 % \DoNotIndex{\newcommand,\newenvironment}
 %
@@ -256,7 +257,7 @@
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
 \RequirePackage{pgf}
-\ProvidesExplPackage {spath3} {2021/02/05} {2.2} {Functions for
+\ProvidesExplPackage {spath3} {2021/02/21} {2.4} {Functions for
 manipulating PGF soft paths}
 \RequirePackage{xparse}
 %    \end{macrocode}
@@ -1756,7 +1757,7 @@
 {
   \spath_splice_between:NVnn #1#1{#2}{#3}
 }
-\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn}
+\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
 \cs_new_protected_nopar:Npn \spath_gsplice_between:Nnnn #1#2#3#4
 {
   \@@_splice_between:nnn {#2}{#3}{#4}
@@ -1768,7 +1769,7 @@
 {
   \spath_gsplice_between:NVnn #1#1{#2}{#3}
 }
-\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv}
+\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1919,7 +1920,7 @@
 {
   \spath_append_no_move:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv, cV}
 \cs_new_protected_nopar:Npn \spath_gappend_no_move:Nnn #1#2#3
 {
   \@@_append_no_move:nn {#2}{#3}
@@ -1931,7 +1932,7 @@
 {
   \spath_gappend_no_move:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv, cV}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1953,7 +1954,7 @@
 {
   \spath_append:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv, cV}
 \cs_new_protected_nopar:Npn \spath_gappend:Nnn #1#2#3
 {
   \tl_gset:Nn #1 {#2}
@@ -1964,7 +1965,7 @@
 {
   \spath_gappend:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv, cV}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2235,6 +2236,128 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% }
+% Replace any line segments by B\'ezier curves.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_replace_lines:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \tl_clear:N \l_@@_tmpb_tl
+  \dim_set:Nn \l_@@_tmpa_dim {0pt}
+  \dim_set:Nn \l_@@_tmpb_dim {0pt}
+
+  \bool_do_until:nn
+  {
+    \tl_if_empty_p: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_@@_tmpa_tl {2}}
+    \tl_set:Nx \l_@@_tmpe_tl {\tl_item:Nn \l_@@_tmpa_tl {3}}
+
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_lineto_tl
+    {
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            2/3 * (\l_@@_tmpa_dim)
+            +
+            1/3 * (\l_@@_tmpd_tl)
+          }
+        }
+      }
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            2/3 * (\l_@@_tmpb_dim)
+            +
+            1/3 * (\l_@@_tmpe_tl)
+          }
+        }
+      }
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            1/3 * (\l_@@_tmpa_dim)
+            +
+            2/3 * (\l_@@_tmpd_tl)
+          }
+        }
+      }
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            1/3 * (\l_@@_tmpb_dim)
+            +
+            2/3 * (\l_@@_tmpe_tl)
+          }
+        }
+      }
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+    }
+    {
+      \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+    }
+
+    \dim_set:Nn \l_@@_tmpa_dim {\l_@@_tmpd_tl}
+    \dim_set:Nn \l_@@_tmpb_dim {\l_@@_tmpe_tl}
+    
+    \prg_replicate:nn {3}
+    {
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \@@_replace_lines:n {V}
+\cs_new_protected_nopar:Npn \spath_replace_lines:Nn #1#2
+{
+  \@@_replace_lines:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_replace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_replace_lines:N #1
+{
+  \spath_replace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_replace_lines:N {c}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:Nn #1#2
+{
+  \@@_replace_lines:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_greplace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:N #1
+{
+  \spath_greplace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_greplace_lines:N {c}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
 % \spath_remove_empty_components:Nn,
 % \spath_remove_empty_components:N,
 % \spath_gremove_empty_components:Nn,
@@ -4709,9 +4832,9 @@
 \cs_generate_variant:Nn \spath_show:n {V, v}
 %    \end{macrocode}
 % \end{macro}
-
-% \subsubsection{PGF and TikZ Interface Functions}
 %
+% \subsection{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}[internal]{
@@ -4845,6 +4968,7 @@
   \tl_clear_new:c {tikz at timer}
   \tl_set:cn {tikz at timer}
   {
+    \pgftransformreset
     \spath_reallength:Nn \l_@@_tmpa_int {#1}
     \tl_set_eq:Nc \l_@@_tmpb_tl {tikz at time}
     \tl_set:Nx \l_@@_tmpb_tl
@@ -4927,7 +5051,10 @@
 %
 %    \begin{macrocode}
 \msg_new:nnn { spath3 } { missing soft path } { Soft~ path~ #1~ doesn't~ exist }
-\msg_new:nnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty }
+\msg_new:nnnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty}
+{If~ it~ was~ defined~ inside~ a~ group,~ try~ using~ "save~ global". }
+\msg_new:nnn { spath3 } { load intersections }
+{ You~ need~ to~ load~ the~ "intersections"~ library~ to~ work~ with~ intersections }
 %    \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.
@@ -4990,6 +5117,73 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{
+% \@@_tikzset:n
+% }
+% Wrapper around \Verb+\tikzset+ for expansion.
+% \begin{macrocode}
+\cs_set_eq:NN \@@_tikzset:n \tikzset
+\cs_generate_variant:Nn \@@_tikzset:n {V, v}
+%    \end{macrocode}
+% \end{macro}
+%
+% When joining two paths we provide a set of options for how to process the second path.
+%
+%    \begin{macrocode}
+\bool_new:N \l_@@_reverse_bool
+\bool_new:N \l_@@_weld_bool
+\bool_new:N \l_@@_move_bool
+\bool_new:N \l_@@_global_bool
+\tl_new:N \l_@@_joinpath_tl
+\tl_new:N \l_@@_transformation_tl
+
+\cs_new_protected_nopar:Npn \@@_set_bool:Nn #1#2
+{
+  \tl_if_eq:nnTF {#2}{false}
+  {
+    \bool_set_false:N #1
+  }
+  {
+    \bool_set_true:N #1
+  }
+}
+\tikzset {
+  spath/join/.is~ family,
+  spath/join/.cd,
+  reverse/.code = {
+    \@@_set_bool:Nn \l_@@_reverse_bool {#1}
+  },
+  reverse/.default = true,
+  weld/.code = {
+    \@@_set_bool:Nn \l_@@_weld_bool {#1}
+  },
+  weld/.default = true,
+  no~ weld/.code = {
+    \@@_set_bool:Nn \l_@@_weld_bool {#1}
+    \bool_set:Nn \l_@@_weld_bool {! \l_@@_weld_bool}
+  },
+  no~ weld/.default = true,
+  move/.code = {
+    \@@_set_bool:Nn \l_@@_move_bool {#1}
+  },
+  move/.default = true,
+  no~ move/.code = {
+    \@@_set_bool:Nn \l_@@_move_bool {#1}
+    \bool_set:Nn \l_@@_move_bool {! \l_@@_move_bool}
+  },
+  no~ move/.default = true,
+  global/.code = {
+    \@@_set_bool:Nn \l_@@_global_bool {#1}
+  },
+  global/.default = true,
+  transform/.store~in=\l_@@_transformation_tl,
+  .unknown/.code = {
+    \tl_set_eq:NN \l_@@_joinpath_tl \pgfkeyscurrentname
+  }
+}
+%    \end{macrocode}
+%
+%
 % When we split a soft path into components, we make it a comma separated list so that it can be fed into a \Verb+\foreach+ loop.
 % This can also make it possible to extract a single component, but to do this we need a wrapper around \Verb+\clist_item:Nn+ (there doesn't appear to be a PGF way of getting an item of a CS list).
 %
@@ -5042,6 +5236,15 @@
       \l_@@_tmpa_tl
     }
   },
+  save~ global/.code={
+    \tikz at 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
+    }
+  },
   clone/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
@@ -5070,15 +5273,6 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #2 }
     }
   },
-  save~ global/.code={
-    \tikz at 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.
@@ -5097,77 +5291,152 @@
   },
 %    \end{macrocode}
 %
-% Restores a soft path to the current path.
+% Exports the path as an SVG file.
 %
 %    \begin{macrocode}
-  restore/.code={
+  export~ to~ svg/.code={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
-      \tl_if_empty:cTF
+      \spath_export_to_svg:nv {#1}
       {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      {
-        \tl_clear:N \l_@@_tmpa_tl
-        \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
-        \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
-        \spath_set_current_path:V \l_@@_tmpa_tl
-        \spath_set_tikz_data:V \l_@@_tmpa_tl
-        \msg_warning:nnn { spath3 } { empty soft path } { #1 }
-      }
-      {
-        \spath_set_current_path:c
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-        \spath_set_tikz_data:v
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      }
     }
     {
-      \tl_clear:N \l_@@_tmpa_tl
-      \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
-      \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
-      \spath_set_current_path:V \l_@@_tmpa_tl
-      \spath_set_tikz_data:V \l_@@_tmpa_tl
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
 %    \end{macrocode}
 %
-% Restores the reverse of a soft path to the current path.
+% Inserts the named path at the current point in the path, with options for how this is accomplished.
+% The inserted path can be transformed, reversed, moved to the current point, and welded to the current path.
+% If this is used before the path has been started then it becomes the start of the path (and the ``current point'' is taken as the origin).
 %
+%
 %    \begin{macrocode}
-  restore~ reverse/.code={
+  use/.code={
+    \bool_set_false:N \l_@@_reverse_bool
+    \bool_set_false:N \l_@@_weld_bool
+    \bool_set_false:N \l_@@_move_bool
+    \tl_clear:N \l_@@_joinpath_tl
+    \tl_clear:N \l_@@_transformation_tl
+    \tikzset{
+      spath/join/.cd,
+      #1
+    }
+
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
-      \tl_if_empty:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \tl_use:N \l_@@_prefix_tl
+      \tl_use:N \l_@@_joinpath_tl
+      \tl_use:N \l_@@_suffix_tl
+    }
+    {
+      \tl_if_empty:cT
       {
-        \tl_clear:N \l_@@_tmpa_tl
-        \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
-        \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
-        \spath_set_current_path:V \l_@@_tmpa_tl
-        \spath_set_tikz_data:V \l_@@_tmpa_tl
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_joinpath_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
         \msg_warning:nnn { spath3 } { empty soft path } { #1 }
       }
+      \tl_set_eq:Nc \l_@@_joinpath_tl
       {
-        \spath_reverse:Nv
-        \l_@@_reverse_tl
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-        \spath_set_current_path:N \l_@@_reverse_tl
-        \spath_set_tikz_data:V \l_@@_reverse_tl
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_joinpath_tl
+        \tl_use:N \l_@@_suffix_tl
       }
+      \spath_get_current_path:N \l_@@_current_tl
+      
+      \bool_if:NT \l_@@_reverse_bool
+      {
+        \spath_reverse:N \l_@@_joinpath_tl
+      }
+      
+      \tl_if_empty:NF \l_@@_transformation_tl
+      {
+        \group_begin:
+        \pgftransformreset
+        \@@_tikzset:V \l_@@_transformation_tl
+        \pgfgettransform \l_@@_tmpa_tl
+        \tl_gset:Nn \g_@@_smuggle_tl
+        {
+          \spath_transform:Nnnnnnn
+          \l_@@_joinpath_tl
+        }
+        \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
+        \group_end:
+        \tl_use:N \g_@@_smuggle_tl
+      }
+
+      \bool_if:NT \l_@@_move_bool
+      {
+        \tl_if_empty:NTF \l_@@_current_tl
+        {
+          \tl_set:Nn \l_@@_tmpc_tl { {0pt} {0pt} }
+        }
+        {
+          \spath_finalpoint:NV
+          \l_@@_tmpc_tl
+          \l_@@_current_tl
+        }
+        \spath_translate_to:NV \l_@@_joinpath_tl \l_@@_tmpc_tl
+      }
+
+      \tl_if_empty:NTF \l_@@_current_tl
+      {
+        \tl_if_empty:NTF \l_@@_joinpath_tl
+        {
+          \tl_set_eq:NN \l_@@_current_tl \c_spath_moveto_tl
+          \tl_put_right:Nn \l_@@_current_tl {{0pt}{0pt}}
+        }
+        {
+          \tl_set_eq:NN \l_@@_current_tl \l_@@_joinpath_tl
+        }
+      }
+      {
+      
+        \tl_clear:N \l_@@_tmpa_tl
+        \tl_set:Nn \l_@@_tmpa_tl {spath_}
+
+        \tl_put_right:Nn \l_@@_tmpa_tl {append}
+
+        \bool_if:NT \l_@@_weld_bool
+        {
+          \tl_put_right:Nn \l_@@_tmpa_tl {_no_move}
+        }
+        \tl_put_right:Nn \l_@@_tmpa_tl {:NV}
+        
+        \use:c {\tl_use:N \l_@@_tmpa_tl }
+        \l_@@_current_tl
+        \l_@@_joinpath_tl
+      }
+
+      \spath_set_current_path:N \l_@@_current_tl
+      \spath_set_tikz_data:V \l_@@_joinpath_tl
     }
     {
-      \tl_clear:N \l_@@_tmpa_tl
-      \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
-      \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
-      \spath_set_current_path:V \l_@@_tmpa_tl
-      \spath_set_tikz_data:V \l_@@_tmpa_tl
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nnx
+      { spath3 }
+      { missing soft path }
+      {\tl_use:N \l_@@_joinpath_tl }
     }
   },
 %    \end{macrocode}
 %
+% Some aliases for the above.
+%
+%    \begin{macrocode}
+  restore/.style={/tikz/spath/use={#1}},
+  restore~ reverse/.style={/tikz/spath/use={reverse, #1}},
+  append/.style={/tikz/spath/use={move, weld, #1}},
+  append~ no~ move/.style={/tikz/spath/use={weld, #1}},
+  append~ reverse/.style={/tikz/spath/use={move, weld, reverse, #1}},
+  append~ reverse~ no~ move/.style={/tikz/spath/use={weld, reverse, #1}},
+  insert/.style={/tikz/spath/use={#1}},
+  insert~ reverse/.style={/tikz/spath/use={reverse, #1}},
+%    \end{macrocode}
+%
 % Diagnostic, show the current path in the terminal and log.
 %
 %    \begin{macrocode}
@@ -5204,45 +5473,99 @@
   },
 %    \end{macrocode}
 %
-% Appends the named path to the current path with a weld.
+% This joins a path on to an existing path, possibly modifying it first.
+% The possible options are the same as those for \Verb+use+.
+% It is possible to specify the same path both for the initial and the joining path as a copy is made internally first.
 %
 %    \begin{macrocode}
-  append/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    {
-      \spath_get_current_path:N \l_@@_current_tl
-      \spath_finalpoint:NV \l_@@_tmpa_tl \l_@@_current_tl
-      \tl_set_eq:Nc
-      \l_@@_tmpb_tl
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \spath_translate_to:NV \l_@@_tmpb_tl \l_@@_tmpa_tl
-      \spath_append_no_move:NV \l_@@_current_tl \l_@@_tmpb_tl
-      \spath_set_current_path:N \l_@@_current_tl
-      \spath_set_tikz_data:V \l_@@_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
-% Joins the second named path to the first.
-%
-%    \begin{macrocode}
   join~ with/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      \bool_set_false:N \l_@@_reverse_bool
+      \bool_set_false:N \l_@@_weld_bool
+      \bool_set_false:N \l_@@_move_bool
+      \bool_set_false:N \l_@@_global_bool
+      \tl_clear:N \l_@@_joinpath_tl
+      \tl_clear:N \l_@@_transformation_tl
+      \tikzset{
+        spath/join/.cd,
+        #2
+      }
+
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_append:cv
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_joinpath_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
+        \tl_set_eq:Nc \l_@@_joinpath_tl
+        {
+          \tl_use:N \l_@@_prefix_tl
+          \tl_use:N \l_@@_joinpath_tl
+          \tl_use:N \l_@@_suffix_tl
+        }
+        
+        \bool_if:NT \l_@@_reverse_bool
+        {
+          \spath_reverse:N \l_@@_joinpath_tl
+        }
+
+        \tl_if_empty:NF \l_@@_transformation_tl
+        {
+          \group_begin:
+          \pgftransformreset
+          \@@_tikzset:V \l_@@_transformation_tl
+          \pgfgettransform \l_@@_tmpa_tl
+          \tl_gset:Nn \g_@@_smuggle_tl
+          {
+            \spath_transform:Nnnnnnn
+            \l_@@_joinpath_tl
+          }
+          \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
+          \group_end:
+          \tl_use:N \g_@@_smuggle_tl
+        }
+
+        \bool_if:NT \l_@@_move_bool
+        {
+          \spath_finalpoint:Nv
+          \l_@@_tmpc_tl
+          {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+          \spath_translate_to:NV \l_@@_joinpath_tl \l_@@_tmpc_tl
+        }
+
+        \tl_clear:N \l_@@_tmpa_tl
+        \tl_set:Nn \l_@@_tmpa_tl {spath_}
+
+        \bool_if:NT \l_@@_global_bool
+        {
+          \tl_put_right:Nn \l_@@_tmpa_tl {g}
+        }
+
+        \tl_put_right:Nn \l_@@_tmpa_tl {append}
+
+        \bool_if:NT \l_@@_weld_bool
+        {
+          \tl_put_right:Nn \l_@@_tmpa_tl {_no_move}
+        }
+        \tl_put_right:Nn \l_@@_tmpa_tl {:cV}
+
+        \cs_if_exist:cF {\tl_use:N \l_@@_tmpa_tl}
+        {
+          \tl_show:N \l_@@_tmpa_tl
+        }
+        
+        \use:c {\tl_use:N \l_@@_tmpa_tl }
         {\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}
+        \l_@@_joinpath_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        {\tl_use:N \l_@@_joinpath_tl }
       }
     }
     {
@@ -5305,113 +5628,6 @@
   },
 %    \end{macrocode}
 %
-% Appends the reversal of the path to the current path.
-%
-%    \begin{macrocode}
-  append~ reverse/.code={
-    \tl_if_exist:cTF
-    {\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_finalpoint:NV \l_@@_tmpa_tl \l_@@_current_tl
-      \spath_translate_to:NV \l_@@_reverse_tl \l_@@_tmpa_tl
-      \spath_append_no_move:NV \l_@@_current_tl \l_@@_reverse_tl
-      \spath_set_current_path:N \l_@@_current_tl
-      \spath_set_tikz_data:V \l_@@_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },    
-%    \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:cTF
-    {\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_data:v
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
-% Inserts the reverse of the named path.
-% 
-%    \begin{macrocode}
-  insert~ reverse/.code={
-    \tl_if_exist:cTF
-    {\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_data:V \l_@@_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
-% Appends the named path to the current path without translating it.
-%
-%    \begin{macrocode}
-  append~ no~ move/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    {
-      \spath_get_current_path:N \l_@@_current_tl
-      \spath_append_no_move: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_data:v
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
-% Appends the reverse of the named path without translating it.
-% 
-%    \begin{macrocode}
-  append~ reverse~ no~ move/.code={
-    \tl_if_exist:cTF
-    {\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_no_move:NV \l_@@_current_tl \l_@@_reverse_tl
-      \spath_set_current_path:N \l_@@_current_tl
-      \spath_set_tikz_data:V \l_@@_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
 % Adjust a path to span between two points.
 %  
 %    \begin{macrocode}
@@ -5519,29 +5735,89 @@
 %    \end{macrocode}
 %
 % Join the components of a path by splicing in the second path whenever the components are sufficiently far apart.
+% The third argument is a list of components to splice after, if it is empty then all components are used and a spot weld is done first so that the splicing only happens if there is an actual gap.
 %
+% The \Verb+upright+ versions will join with the reflection of the splice path if it detects that the gap is ``upside-down''.
+%
+%
 %    \begin{macrocode}
   join~ components~ with/.code~2~args={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_spot_weld_components:c
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_tmpc_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l_@@_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        }
 
         \spath_components_to_seq:Nv
         \l_@@_tmpa_seq
         {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
 
+        \seq_gclear:N \g_@@_tmpa_seq
+        
+        \tl_if_empty:NTF \l_@@_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+          {
+            \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_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
-      
-        \seq_map_inline:Nn \l_@@_tmpa_seq
+        \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+        \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
         {
-          \spath_splice_between:Nvn \l_@@_tmpa_tl
-          {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
-          {##1}
+          \int_compare:nTF
+          {
+            ##1 == \l_@@_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+            {
+              \tl_set:Nn \l_@@_tmpb_tl {-1}
+            }
+            \spath_splice_between:Nvn \l_@@_tmpa_tl
+            {
+              \tl_use:N \l_@@_prefix_tl
+              \tl_use:N \l_@@_tmpc_tl
+              \tl_use:N \l_@@_suffix_tl
+            }
+            {##2}
+          }
+          {
+            \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+          }
         }
         \tl_set_eq:cN
         {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
@@ -5548,7 +5824,10 @@
         \l_@@_tmpa_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l_@@_tmpc_tl }
       }
     }
     {
@@ -5559,30 +5838,204 @@
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_spot_gweld_components:c
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_tmpc_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l_@@_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        }
+
+        \spath_components_to_seq:Nv
+        \l_@@_tmpa_seq
         {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+        \seq_gclear:N \g_@@_tmpa_seq
         
+        \tl_if_empty:NTF \l_@@_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+          {
+            \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_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+        \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+        \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l_@@_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+            {
+              \tl_set:Nn \l_@@_tmpb_tl {-1}
+            }
+            \spath_splice_between:Nvn \l_@@_tmpa_tl
+            {
+              \tl_use:N \l_@@_prefix_tl
+              \tl_use:N \l_@@_tmpc_tl
+              \tl_use:N \l_@@_suffix_tl
+            }
+            {##2}
+          }
+          {
+            \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+          }
+        }
+        \tl_gset_eq:cN
+        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \l_@@_tmpa_tl
+      }
+      {
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l_@@_tmpc_tl }
+      }
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
+  join~ components~ upright~ with/.code~2~args={
+    \tl_if_exist:cTF
+    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
+      \tl_if_exist:cTF
+      {
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_tmpc_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l_@@_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        }
+
         \spath_components_to_seq:Nv
         \l_@@_tmpa_seq
         {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
 
+        \seq_gclear:N \g_@@_tmpa_seq
+        
+        \tl_if_empty:NTF \l_@@_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+          {
+            \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_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
-      
-        \seq_map_inline:Nn \l_@@_tmpa_seq
+        \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+        \tl_set_eq:Nc \l_@@_tmpc_tl
         {
-          \spath_gsplice_between:Nvn \l_@@_tmpa_tl
-          {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
-          {##1}
+          \tl_use:N \l_@@_prefix_tl
+          \tl_use:N \l_@@_tmpc_tl
+          \tl_use:N \l_@@_suffix_tl
         }
+        \spath_transform:NVnnnnnn \l_@@_tmpd_tl \l_@@_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+        
+        \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l_@@_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+            {
+              \tl_set:Nn \l_@@_tmpb_tl {-1}
+            }
+            \spath_finalpoint:NV \l_@@_tmpe_tl \l_@@_tmpa_tl
+            \spath_initialpoint:Nn \l_@@_tmpf_tl {##2}
+
+            \dim_compare:nTF
+            {
+              \tl_item:Nn \l_@@_tmpe_tl {1}
+              >
+              \tl_item:Nn \l_@@_tmpf_tl {1}
+            }
+            {
+              \spath_splice_between:NVn
+              \l_@@_tmpa_tl
+              \l_@@_tmpd_tl
+              {##2}
+            }
+            {
+              \spath_splice_between:NVn
+              \l_@@_tmpa_tl
+              \l_@@_tmpc_tl
+              {##2}
+            }
+          }
+          {
+            \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+          }
+        }
         \tl_set_eq:cN
         {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
         \l_@@_tmpa_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l_@@_tmpc_tl }
       }
     }
     {
@@ -5589,6 +6042,121 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
+  join~ components~ globally~ upright~ with/.code~2~args={
+    \tl_if_exist:cTF
+    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
+      \tl_if_exist:cTF
+      {
+        \tl_use:N \l_@@_prefix_tl
+        \tl_use:N \l_@@_tmpc_tl
+        \tl_use:N \l_@@_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l_@@_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        }
+
+        \spath_components_to_seq:Nv
+        \l_@@_tmpa_seq
+        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+        \seq_gclear:N \g_@@_tmpa_seq
+        
+        \tl_if_empty:NTF \l_@@_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+          {
+            \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_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+        \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+        \tl_set_eq:Nc \l_@@_tmpc_tl
+        {
+          \tl_use:N \l_@@_prefix_tl
+          \tl_use:N \l_@@_tmpc_tl
+          \tl_use:N \l_@@_suffix_tl
+        }
+        \spath_transform:NVnnnnnn \l_@@_tmpd_tl \l_@@_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+        
+        \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l_@@_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+            {
+              \tl_set:Nn \l_@@_tmpb_tl {-1}
+            }
+            \spath_finalpoint:NV \l_@@_tmpe_tl \l_@@_tmpa_tl
+            \spath_initialpoint:Nn \l_@@_tmpf_tl {##2}
+
+            \dim_compare:nTF
+            {
+              \tl_item:Nn \l_@@_tmpe_tl {1}
+              >
+              \tl_item:Nn \l_@@_tmpf_tl {1}
+            }
+            {
+              \spath_splice_between:NVn
+              \l_@@_tmpa_tl
+              \l_@@_tmpd_tl
+              {##2}
+            }
+            {
+              \spath_splice_between:NVn
+              \l_@@_tmpa_tl
+              \l_@@_tmpc_tl
+              {##2}
+            }
+          }
+          {
+            \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+          }
+        }
+        \tl_gset_eq:cN
+        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \l_@@_tmpa_tl
+      }
+      {
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l_@@_tmpc_tl }
+      }
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
 %    \end{macrocode}
 %
 % Close a path.
@@ -5790,22 +6358,6 @@
   },
 %    \end{macrocode}
 %
-% Exports the path as an SVG file.
-%
-%    \begin{macrocode}
-  export~ to~ svg/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    {
-      \spath_export_to_svg:nv {#1}
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-%    \end{macrocode}
-%
 % Transforms the named path using TikZ transformation specifications.
 %
 %    \begin{macrocode}
@@ -5858,40 +6410,58 @@
 %    \begin{macrocode}
   split~ at~ intersections~ with/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_split_path_at_intersections:cv
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        {
+          \spath_split_path_at_intersections: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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ intersections~ with/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      tikz at library@intersections at loaded
+    }
+    {
+    \tl_if_exist:cTF
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_gsplit_path_at_intersections:cv
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        {
+          \spath_gsplit_path_at_intersections: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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
 %    \end{macrocode}
@@ -5901,40 +6471,58 @@
 %    \begin{macrocode}
   split~ at~ intersections/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      {\tl_use:N \l_@@_prefix_tl #1 \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_if_exist:cTF
         {\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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ intersections/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
       {
-        \spath_gsplit_at_intersections:cc
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        {
+          \spath_gsplit_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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
 %    \end{macrocode}
@@ -5944,24 +6532,42 @@
 %    \begin{macrocode}
   split~ at~ self~ intersections/.code={
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
-      \spath_split_at_self_intersections:c
+      tikz at library@intersections at loaded
+    }
+    {
+      \tl_if_exist:cTF
       {\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}
+      }
+      {
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ self~ intersections/.code={
     \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
-      \spath_gsplit_at_self_intersections:c
+      tikz at library@intersections at loaded
+    }
+    {
+      \tl_if_exist:cTF
       {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      {
+        \spath_gsplit_at_self_intersections:c
+        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      }
+      {
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
 %    \end{macrocode}
@@ -6069,29 +6675,53 @@
 % 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}{
+  insert~ gaps~ after~ components/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
       \group_begin:
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
       \seq_gclear:N \g_@@_tmpa_seq
       \seq_gclear:N \g_@@_tmpb_seq
       \spath_numberofcomponents:Nv \l_@@_tmpa_int
       {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \foreach \l_@@_tmpa_tl in {#3}
+
+      \spath_components_to_seq:Nv
+      \l_@@_tmpa_seq
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      
+      \tl_if_empty:NTF \l_@@_tmpd_tl
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
-        \seq_gput_right:Nx
-        \g_@@_tmpb_seq
-        {\int_eval:n
-          {
-            \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+        \int_step_inline:nnnn {1}{1} { \l_@@_tmpa_int - 1 }
+        {
+          \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          \seq_gput_right:Nx
+          \g_@@_tmpb_seq
+          {\int_eval:n {##1 + 1}}
+        }
+      }
+      {
+        \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+        {
+          \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+          \seq_gput_right:Nx
+          \g_@@_tmpb_seq
+          {\int_eval:n
+            {
+              \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 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
       {
@@ -6098,11 +6728,11 @@
         \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}
+          \spath_shorten_at_end:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
         }
         \seq_if_in:NnT \g_@@_tmpb_seq {##1}
         {
-          \spath_shorten_at_start:Nn \l_@@_tmpa_tl {#2/2}
+          \spath_shorten_at_start:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
         }
         \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
       }
@@ -6117,30 +6747,53 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  insert~ gaps~ globally~ after~ components/.code~ n~ args={3}{
+  insert~ gaps~ globally~ after~ components/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
     {
       \group_begin:
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l_@@_tmpc_tl {#2}
+        \tl_clear:N \l_@@_tmpd_tl
+      }
       \seq_gclear:N \g_@@_tmpa_seq
       \seq_gclear:N \g_@@_tmpb_seq
       \spath_numberofcomponents:Nv \l_@@_tmpa_int
       {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \foreach \l_@@_tmpa_tl in {#3}
+
+      \spath_components_to_seq:Nv
+      \l_@@_tmpa_seq
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      
+      \tl_if_empty:NTF \l_@@_tmpd_tl
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
-        \seq_gput_right:Nx
-        \g_@@_tmpb_seq
+        \int_step_inline:nnnn {1}{1} { \l_@@_tmpa_int - 1 }
         {
-          \int_eval:n
-          {
-            \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+          \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+          \seq_gput_right:Nx
+          \g_@@_tmpb_seq
+          {\int_eval:n {##1 + 1}}
+        }
+      }
+      {
+        \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+        {
+          \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+          \seq_gput_right:Nx
+          \g_@@_tmpb_seq
+          {\int_eval:n
+            {
+              \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 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
       {
@@ -6147,11 +6800,11 @@
         \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}
+          \spath_shorten_at_end:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
         }
         \seq_if_in:NnT \g_@@_tmpb_seq {##1}
         {
-          \spath_shorten_at_start:Nn \l_@@_tmpa_tl {#2/2}
+          \spath_shorten_at_start:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
         }
         \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
       }
@@ -6250,7 +6903,34 @@
   },
 %    \end{macrocode}
 %
+% Replace all line segments by B\'ezier curves.
 %
+%    \begin{macrocode}
+  replace~ lines/.code={
+    \tl_if_exist:cTF
+    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    {
+      \spath_replace_lines:c
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
+  replace~ lines~ globally/.code={
+    \tl_if_exist:cTF
+    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    {
+      \spath_greplace_lines:c
+      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
+%    \end{macrocode}
+%
+%
 % Join the specified components together, joining each to its previous one.
 %
 %    \begin{macrocode}
@@ -6547,7 +7227,10 @@
     }
   }
   {
-    \msg_warning:nnx { spath3 } { missing soft path } { \tl_use:N \l_@@_tmpa_tl }
+    \msg_warning:nnx
+    { spath3 }
+    { missing soft path }
+    { \tl_use:N \l_@@_tmpa_tl }
     \tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin
   }
   \group_end:

Modified: trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty	2021-02-22 14:22:20 UTC (rev 57841)
+++ trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty	2021-02-22 21:52:11 UTC (rev 57842)
@@ -15,7 +15,7 @@
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
 \RequirePackage{pgf}
-\ProvidesExplPackage {spath3} {2021/02/05} {2.2} {Functions for
+\ProvidesExplPackage {spath3} {2021/02/21} {2.4} {Functions for
 manipulating PGF soft paths}
 \RequirePackage{xparse}
 \cs_new_protected:Nn \__spath_tl_put_right_braced:Nn
@@ -1226,7 +1226,7 @@
 {
   \spath_splice_between:NVnn #1#1{#2}{#3}
 }
-\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn}
+\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
 \cs_new_protected_nopar:Npn \spath_gsplice_between:Nnnn #1#2#3#4
 {
   \__spath_splice_between:nnn {#2}{#3}{#4}
@@ -1238,7 +1238,7 @@
 {
   \spath_gsplice_between:NVnn #1#1{#2}{#3}
 }
-\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv}
+\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
 \cs_new_protected_nopar:Npn \__spath_close_with:nn #1#2
 {
   \group_begin:
@@ -1355,7 +1355,7 @@
 {
   \spath_append_no_move:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv, cV}
 \cs_new_protected_nopar:Npn \spath_gappend_no_move:Nnn #1#2#3
 {
   \__spath_append_no_move:nn {#2}{#3}
@@ -1367,7 +1367,7 @@
 {
   \spath_gappend_no_move:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv, cV}
 \cs_new_protected_nopar:Npn \spath_append:Nnn #1#2#3
 {
   \tl_set:Nn #1 {#2}
@@ -1378,7 +1378,7 @@
 {
   \spath_append:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv, cV}
 \cs_new_protected_nopar:Npn \spath_gappend:Nnn #1#2#3
 {
   \tl_gset:Nn #1 {#2}
@@ -1389,7 +1389,7 @@
 {
   \spath_gappend:NVn #1#1{#2}
 }
-\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv, cV}
 \cs_new_protected_nopar:Npn \spath_prepend_no_move:Nnn #1#2#3
 {
   \spath_append_no_move:Nnn #1{#3}{#2}
@@ -1596,6 +1596,117 @@
 {
   \spath_gopen:NV #1#1
 }
+\cs_new_protected_nopar:Npn \__spath_replace_lines:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \tl_clear:N \l__spath_tmpb_tl
+  \dim_set:Nn \l__spath_tmpa_dim {0pt}
+  \dim_set:Nn \l__spath_tmpb_dim {0pt}
+
+  \bool_do_until: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_tmpa_tl {2}}
+    \tl_set:Nx \l__spath_tmpe_tl {\tl_item:Nn \l__spath_tmpa_tl {3}}
+
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_lineto_tl
+    {
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_curvetoa_tl
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            2/3 * (\l__spath_tmpa_dim)
+            +
+            1/3 * (\l__spath_tmpd_tl)
+          }
+        }
+      }
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            2/3 * (\l__spath_tmpb_dim)
+            +
+            1/3 * (\l__spath_tmpe_tl)
+          }
+        }
+      }
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_curvetob_tl
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            1/3 * (\l__spath_tmpa_dim)
+            +
+            2/3 * (\l__spath_tmpd_tl)
+          }
+        }
+      }
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n
+          {
+            1/3 * (\l__spath_tmpb_dim)
+            +
+            2/3 * (\l__spath_tmpe_tl)
+          }
+        }
+      }
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_curveto_tl
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpe_tl
+    }
+    {
+      \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpe_tl
+    }
+
+    \dim_set:Nn \l__spath_tmpa_dim {\l__spath_tmpd_tl}
+    \dim_set:Nn \l__spath_tmpb_dim {\l__spath_tmpe_tl}
+
+    \prg_replicate:nn {3}
+    {
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+  }
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \__spath_replace_lines:n {V}
+\cs_new_protected_nopar:Npn \spath_replace_lines:Nn #1#2
+{
+  \__spath_replace_lines:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_replace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_replace_lines:N #1
+{
+  \spath_replace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_replace_lines:N {c}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:Nn #1#2
+{
+  \__spath_replace_lines:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_greplace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:N #1
+{
+  \spath_greplace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_greplace_lines:N {c}
 \cs_new_protected_nopar:Npn \__spath_remove_empty_components:n #1
 {
   \group_begin:
@@ -3810,7 +3921,6 @@
   }
 }
 \cs_generate_variant:Nn \spath_show:n {V, v}
-
 \cs_new_protected_nopar:Npn \spath_get_current_path:N #1
 {
   \pgfsyssoftpath at getcurrentpath #1
@@ -3898,6 +4008,7 @@
   \tl_clear_new:c {tikz at timer}
   \tl_set:cn {tikz at timer}
   {
+    \pgftransformreset
     \spath_reallength:Nn \l__spath_tmpa_int {#1}
     \tl_set_eq:Nc \l__spath_tmpb_tl {tikz at time}
     \tl_set:Nx \l__spath_tmpb_tl

Modified: trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex	2021-02-22 14:22:20 UTC (rev 57841)
+++ trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex	2021-02-22 21:52:11 UTC (rev 57842)
@@ -25,7 +25,10 @@
 \seq_new:N \g__spath_tmpb_seq
 \bool_new:N \l__spath_draft_bool
 \msg_new:nnn { spath3 } { missing soft path } { Soft~ path~ #1~ doesn't~ exist }
-\msg_new:nnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty }
+\msg_new:nnnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty}
+{If~ it~ was~ defined~ inside~ a~ group,~ try~ using~ "save~ global". }
+\msg_new:nnn { spath3 } { load intersections }
+{ You~ need~ to~ load~ the~ "intersections"~ library~ to~ work~ with~ intersections }
 \tl_set:Nn \l__spath_prefix_tl {tikz at intersect@path at name@}
 \tl_set:Nn \l__spath_suffix_tl {}
 \tl_new:N \g__spath_tikzfinish_tl
@@ -68,6 +71,59 @@
   \tl_set_eq:NN #1 \g__spath_output_tl
   \tl_gclear:N \g__spath_output_tl
 }
+\cs_set_eq:NN \__spath_tikzset:n \tikzset
+\cs_generate_variant:Nn \__spath_tikzset:n {V, v}
+\bool_new:N \l__spath_reverse_bool
+\bool_new:N \l__spath_weld_bool
+\bool_new:N \l__spath_move_bool
+\bool_new:N \l__spath_global_bool
+\tl_new:N \l__spath_joinpath_tl
+\tl_new:N \l__spath_transformation_tl
+
+\cs_new_protected_nopar:Npn \__spath_set_bool:Nn #1#2
+{
+  \tl_if_eq:nnTF {#2}{false}
+  {
+    \bool_set_false:N #1
+  }
+  {
+    \bool_set_true:N #1
+  }
+}
+\tikzset {
+  spath/join/.is~ family,
+  spath/join/.cd,
+  reverse/.code = {
+    \__spath_set_bool:Nn \l__spath_reverse_bool {#1}
+  },
+  reverse/.default = true,
+  weld/.code = {
+    \__spath_set_bool:Nn \l__spath_weld_bool {#1}
+  },
+  weld/.default = true,
+  no~ weld/.code = {
+    \__spath_set_bool:Nn \l__spath_weld_bool {#1}
+    \bool_set:Nn \l__spath_weld_bool {! \l__spath_weld_bool}
+  },
+  no~ weld/.default = true,
+  move/.code = {
+    \__spath_set_bool:Nn \l__spath_move_bool {#1}
+  },
+  move/.default = true,
+  no~ move/.code = {
+    \__spath_set_bool:Nn \l__spath_move_bool {#1}
+    \bool_set:Nn \l__spath_move_bool {! \l__spath_move_bool}
+  },
+  no~ move/.default = true,
+  global/.code = {
+    \__spath_set_bool:Nn \l__spath_global_bool {#1}
+  },
+  global/.default = true,
+  transform/.store~in=\l__spath_transformation_tl,
+  .unknown/.code = {
+    \tl_set_eq:NN \l__spath_joinpath_tl \pgfkeyscurrentname
+  }
+}
 \cs_set_eq:NN \getComponentOf \clist_item:Nn
 \tikzset{
   spath/.is~family,
@@ -95,6 +151,15 @@
       \l__spath_tmpa_tl
     }
   },
+  save~ global/.code={
+    \tikz at 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
+    }
+  },
   clone/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
@@ -123,15 +188,6 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #2 }
     }
   },
-  save~ global/.code={
-    \tikz at 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:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -143,67 +199,134 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  restore/.code={
+  export~ to~ svg/.code={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
-      \tl_if_empty:cTF
+      \spath_export_to_svg:nv {#1}
       {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      {
-        \tl_clear:N \l__spath_tmpa_tl
-        \tl_put_right:NV \l__spath_tmpa_tl \c_spath_moveto_tl
-        \tl_put_right:Nn \l__spath_tmpa_tl {{0pt}{0pt}}
-        \spath_set_current_path:V \l__spath_tmpa_tl
-        \spath_set_tikz_data:V \l__spath_tmpa_tl
-        \msg_warning:nnn { spath3 } { empty soft path } { #1 }
-      }
-      {
-        \spath_set_current_path:c
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-        \spath_set_tikz_data:v
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      }
     }
     {
-      \tl_clear:N \l__spath_tmpa_tl
-      \tl_put_right:NV \l__spath_tmpa_tl \c_spath_moveto_tl
-      \tl_put_right:Nn \l__spath_tmpa_tl {{0pt}{0pt}}
-      \spath_set_current_path:V \l__spath_tmpa_tl
-      \spath_set_tikz_data:V \l__spath_tmpa_tl
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  restore~ reverse/.code={
+  use/.code={
+    \bool_set_false:N \l__spath_reverse_bool
+    \bool_set_false:N \l__spath_weld_bool
+    \bool_set_false:N \l__spath_move_bool
+    \tl_clear:N \l__spath_joinpath_tl
+    \tl_clear:N \l__spath_transformation_tl
+    \tikzset{
+      spath/join/.cd,
+      #1
+    }
+
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
-      \tl_if_empty:cTF
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      \tl_use:N \l__spath_prefix_tl
+      \tl_use:N \l__spath_joinpath_tl
+      \tl_use:N \l__spath_suffix_tl
+    }
+    {
+      \tl_if_empty:cT
       {
-        \tl_clear:N \l__spath_tmpa_tl
-        \tl_put_right:NV \l__spath_tmpa_tl \c_spath_moveto_tl
-        \tl_put_right:Nn \l__spath_tmpa_tl {{0pt}{0pt}}
-        \spath_set_current_path:V \l__spath_tmpa_tl
-        \spath_set_tikz_data:V \l__spath_tmpa_tl
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_joinpath_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
         \msg_warning:nnn { spath3 } { empty soft path } { #1 }
       }
+      \tl_set_eq:Nc \l__spath_joinpath_tl
       {
-        \spath_reverse:Nv
-        \l__spath_reverse_tl
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-        \spath_set_current_path:N \l__spath_reverse_tl
-        \spath_set_tikz_data:V \l__spath_reverse_tl
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_joinpath_tl
+        \tl_use:N \l__spath_suffix_tl
       }
+      \spath_get_current_path:N \l__spath_current_tl
+
+      \bool_if:NT \l__spath_reverse_bool
+      {
+        \spath_reverse:N \l__spath_joinpath_tl
+      }
+
+      \tl_if_empty:NF \l__spath_transformation_tl
+      {
+        \group_begin:
+        \pgftransformreset
+        \__spath_tikzset:V \l__spath_transformation_tl
+        \pgfgettransform \l__spath_tmpa_tl
+        \tl_gset:Nn \g__spath_smuggle_tl
+        {
+          \spath_transform:Nnnnnnn
+          \l__spath_joinpath_tl
+        }
+        \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl
+        \group_end:
+        \tl_use:N \g__spath_smuggle_tl
+      }
+
+      \bool_if:NT \l__spath_move_bool
+      {
+        \tl_if_empty:NTF \l__spath_current_tl
+        {
+          \tl_set:Nn \l__spath_tmpc_tl { {0pt} {0pt} }
+        }
+        {
+          \spath_finalpoint:NV
+          \l__spath_tmpc_tl
+          \l__spath_current_tl
+        }
+        \spath_translate_to:NV \l__spath_joinpath_tl \l__spath_tmpc_tl
+      }
+
+      \tl_if_empty:NTF \l__spath_current_tl
+      {
+        \tl_if_empty:NTF \l__spath_joinpath_tl
+        {
+          \tl_set_eq:NN \l__spath_current_tl \c_spath_moveto_tl
+          \tl_put_right:Nn \l__spath_current_tl {{0pt}{0pt}}
+        }
+        {
+          \tl_set_eq:NN \l__spath_current_tl \l__spath_joinpath_tl
+        }
+      }
+      {
+
+        \tl_clear:N \l__spath_tmpa_tl
+        \tl_set:Nn \l__spath_tmpa_tl {spath_}
+
+        \tl_put_right:Nn \l__spath_tmpa_tl {append}
+
+        \bool_if:NT \l__spath_weld_bool
+        {
+          \tl_put_right:Nn \l__spath_tmpa_tl {_no_move}
+        }
+        \tl_put_right:Nn \l__spath_tmpa_tl {:NV}
+
+        \use:c {\tl_use:N \l__spath_tmpa_tl }
+        \l__spath_current_tl
+        \l__spath_joinpath_tl
+      }
+
+      \spath_set_current_path:N \l__spath_current_tl
+      \spath_set_tikz_data:V \l__spath_joinpath_tl
     }
     {
-      \tl_clear:N \l__spath_tmpa_tl
-      \tl_put_right:NV \l__spath_tmpa_tl \c_spath_moveto_tl
-      \tl_put_right:Nn \l__spath_tmpa_tl {{0pt}{0pt}}
-      \spath_set_current_path:V \l__spath_tmpa_tl
-      \spath_set_tikz_data:V \l__spath_tmpa_tl
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nnx
+      { spath3 }
+      { missing soft path }
+      {\tl_use:N \l__spath_joinpath_tl }
     }
   },
+  restore/.style={/tikz/spath/use={#1}},
+  restore~ reverse/.style={/tikz/spath/use={reverse, #1}},
+  append/.style={/tikz/spath/use={move, weld, #1}},
+  append~ no~ move/.style={/tikz/spath/use={weld, #1}},
+  append~ reverse/.style={/tikz/spath/use={move, weld, reverse, #1}},
+  append~ reverse~ no~ move/.style={/tikz/spath/use={weld, reverse, #1}},
+  insert/.style={/tikz/spath/use={#1}},
+  insert~ reverse/.style={/tikz/spath/use={reverse, #1}},
   show~current~path/.code={
     \tikz at addmode{
       \pgfsyssoftpath at getcurrentpath\l__spath_tmpa_tl
@@ -230,37 +353,94 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  append/.code={
-    \tl_if_exist:cTF
-    {\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_finalpoint:NV \l__spath_tmpa_tl \l__spath_current_tl
-      \tl_set_eq:Nc
-      \l__spath_tmpb_tl
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \spath_translate_to:NV \l__spath_tmpb_tl \l__spath_tmpa_tl
-      \spath_append_no_move:NV \l__spath_current_tl \l__spath_tmpb_tl
-      \spath_set_current_path:N \l__spath_current_tl
-      \spath_set_tikz_data:V \l__spath_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
   join~ with/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      \bool_set_false:N \l__spath_reverse_bool
+      \bool_set_false:N \l__spath_weld_bool
+      \bool_set_false:N \l__spath_move_bool
+      \bool_set_false:N \l__spath_global_bool
+      \tl_clear:N \l__spath_joinpath_tl
+      \tl_clear:N \l__spath_transformation_tl
+      \tikzset{
+        spath/join/.cd,
+        #2
+      }
+
       \tl_if_exist:cTF
-      {\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
+        \tl_use:N \l__spath_joinpath_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
+        \tl_set_eq:Nc \l__spath_joinpath_tl
+        {
+          \tl_use:N \l__spath_prefix_tl
+          \tl_use:N \l__spath_joinpath_tl
+          \tl_use:N \l__spath_suffix_tl
+        }
+
+        \bool_if:NT \l__spath_reverse_bool
+        {
+          \spath_reverse:N \l__spath_joinpath_tl
+        }
+
+        \tl_if_empty:NF \l__spath_transformation_tl
+        {
+          \group_begin:
+          \pgftransformreset
+          \__spath_tikzset:V \l__spath_transformation_tl
+          \pgfgettransform \l__spath_tmpa_tl
+          \tl_gset:Nn \g__spath_smuggle_tl
+          {
+            \spath_transform:Nnnnnnn
+            \l__spath_joinpath_tl
+          }
+          \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl
+          \group_end:
+          \tl_use:N \g__spath_smuggle_tl
+        }
+
+        \bool_if:NT \l__spath_move_bool
+        {
+          \spath_finalpoint:Nv
+          \l__spath_tmpc_tl
+          {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+          \spath_translate_to:NV \l__spath_joinpath_tl \l__spath_tmpc_tl
+        }
+
+        \tl_clear:N \l__spath_tmpa_tl
+        \tl_set:Nn \l__spath_tmpa_tl {spath_}
+
+        \bool_if:NT \l__spath_global_bool
+        {
+          \tl_put_right:Nn \l__spath_tmpa_tl {g}
+        }
+
+        \tl_put_right:Nn \l__spath_tmpa_tl {append}
+
+        \bool_if:NT \l__spath_weld_bool
+        {
+          \tl_put_right:Nn \l__spath_tmpa_tl {_no_move}
+        }
+        \tl_put_right:Nn \l__spath_tmpa_tl {:cV}
+
+        \cs_if_exist:cF {\tl_use:N \l__spath_tmpa_tl}
+        {
+          \tl_show:N \l__spath_tmpa_tl
+        }
+
+        \use:c {\tl_use:N \l__spath_tmpa_tl }
         {\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}
+        \l__spath_joinpath_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        {\tl_use:N \l__spath_joinpath_tl }
       }
     }
     {
@@ -311,88 +491,6 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  append~ reverse/.code={
-    \tl_if_exist:cTF
-    {\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_finalpoint:NV \l__spath_tmpa_tl \l__spath_current_tl
-      \spath_translate_to:NV \l__spath_reverse_tl \l__spath_tmpa_tl
-      \spath_append_no_move:NV \l__spath_current_tl \l__spath_reverse_tl
-      \spath_set_current_path:N \l__spath_current_tl
-      \spath_set_tikz_data:V \l__spath_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-  insert/.code={
-    \tl_if_exist:cTF
-    {\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_data:v
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-  insert~ reverse/.code={
-    \tl_if_exist:cTF
-    {\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_data:V \l__spath_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-  append~ no~ move/.code={
-    \tl_if_exist:cTF
-    {\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_no_move: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_data:v
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
-  append~ reverse~ no~ move/.code={
-    \tl_if_exist:cTF
-    {\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_no_move:NV \l__spath_current_tl \l__spath_reverse_tl
-      \spath_set_current_path:N \l__spath_current_tl
-      \spath_set_tikz_data:V \l__spath_reverse_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
   span/.code ~n~ args={3}{
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -488,23 +586,79 @@
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
       \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \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}
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_tmpc_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l__spath_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        }
 
         \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_gclear:N \g__spath_tmpa_seq
+
+        \tl_if_empty:NTF \l__spath_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l__spath_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+          {
+            \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_pop_left:NN \l__spath_tmpa_seq \l__spath_tmpa_tl
+        \seq_gpop_left:NN \g__spath_tmpa_seq \l__spath_tmpb_tl
 
-        \seq_map_inline:Nn \l__spath_tmpa_seq
+        \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
         {
-          \spath_splice_between:Nvn \l__spath_tmpa_tl
-          {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
-          {##1}
+          \int_compare:nTF
+          {
+            ##1 == \l__spath_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpb_tl
+            {
+              \tl_set:Nn \l__spath_tmpb_tl {-1}
+            }
+            \spath_splice_between:Nvn \l__spath_tmpa_tl
+            {
+              \tl_use:N \l__spath_prefix_tl
+              \tl_use:N \l__spath_tmpc_tl
+              \tl_use:N \l__spath_suffix_tl
+            }
+            {##2}
+          }
+          {
+            \tl_put_right:Nn \l__spath_tmpa_tl {##2}
+          }
         }
         \tl_set_eq:cN
         {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -511,7 +665,10 @@
         \l__spath_tmpa_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l__spath_tmpc_tl }
       }
     }
     {
@@ -522,30 +679,204 @@
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
       \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
       {
-        \spath_spot_gweld_components:c
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_tmpc_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l__spath_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        }
+
+        \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_gclear:N \g__spath_tmpa_seq
+
+        \tl_if_empty:NTF \l__spath_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l__spath_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+          {
+            \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_pop_left:NN \l__spath_tmpa_seq \l__spath_tmpa_tl
+        \seq_gpop_left:NN \g__spath_tmpa_seq \l__spath_tmpb_tl
+
+        \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l__spath_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpb_tl
+            {
+              \tl_set:Nn \l__spath_tmpb_tl {-1}
+            }
+            \spath_splice_between:Nvn \l__spath_tmpa_tl
+            {
+              \tl_use:N \l__spath_prefix_tl
+              \tl_use:N \l__spath_tmpc_tl
+              \tl_use:N \l__spath_suffix_tl
+            }
+            {##2}
+          }
+          {
+            \tl_put_right:Nn \l__spath_tmpa_tl {##2}
+          }
+        }
+        \tl_gset_eq:cN
+        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \l__spath_tmpa_tl
+      }
+      {
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l__spath_tmpc_tl }
+      }
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
+  join~ components~ upright~ with/.code~2~args={
+    \tl_if_exist:cTF
+    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
+      \tl_if_exist:cTF
+      {
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_tmpc_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l__spath_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        }
+
         \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_gclear:N \g__spath_tmpa_seq
+
+        \tl_if_empty:NTF \l__spath_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l__spath_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+          {
+            \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_pop_left:NN \l__spath_tmpa_seq \l__spath_tmpa_tl
+        \seq_gpop_left:NN \g__spath_tmpa_seq \l__spath_tmpb_tl
 
-        \seq_map_inline:Nn \l__spath_tmpa_seq
+        \tl_set_eq:Nc \l__spath_tmpc_tl
         {
-          \spath_gsplice_between:Nvn \l__spath_tmpa_tl
-          {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
-          {##1}
+          \tl_use:N \l__spath_prefix_tl
+          \tl_use:N \l__spath_tmpc_tl
+          \tl_use:N \l__spath_suffix_tl
         }
+        \spath_transform:NVnnnnnn \l__spath_tmpd_tl \l__spath_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+
+        \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l__spath_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpb_tl
+            {
+              \tl_set:Nn \l__spath_tmpb_tl {-1}
+            }
+            \spath_finalpoint:NV \l__spath_tmpe_tl \l__spath_tmpa_tl
+            \spath_initialpoint:Nn \l__spath_tmpf_tl {##2}
+
+            \dim_compare:nTF
+            {
+              \tl_item:Nn \l__spath_tmpe_tl {1}
+              >
+              \tl_item:Nn \l__spath_tmpf_tl {1}
+            }
+            {
+              \spath_splice_between:NVn
+              \l__spath_tmpa_tl
+              \l__spath_tmpd_tl
+              {##2}
+            }
+            {
+              \spath_splice_between:NVn
+              \l__spath_tmpa_tl
+              \l__spath_tmpc_tl
+              {##2}
+            }
+          }
+          {
+            \tl_put_right:Nn \l__spath_tmpa_tl {##2}
+          }
+        }
         \tl_set_eq:cN
         {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
         \l__spath_tmpa_tl
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l__spath_tmpc_tl }
       }
     }
     {
@@ -552,6 +883,121 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
+  join~ components~ globally~ upright~ with/.code~2~args={
+    \tl_if_exist:cTF
+    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    {
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
+      \tl_if_exist:cTF
+      {
+        \tl_use:N \l__spath_prefix_tl
+        \tl_use:N \l__spath_tmpc_tl
+        \tl_use:N \l__spath_suffix_tl
+      }
+      {
+        \tl_if_empty:NT \l__spath_tmpd_tl
+        {
+          \spath_spot_weld_components:c
+          {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        }
+
+        \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_gclear:N \g__spath_tmpa_seq
+
+        \tl_if_empty:NTF \l__spath_tmpd_tl
+        {
+          \int_step_inline:nnnn {1}{1} {\seq_count:N \l__spath_tmpa_seq}
+          {
+            \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          }
+        }
+        {
+          \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+          {
+            \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_pop_left:NN \l__spath_tmpa_seq \l__spath_tmpa_tl
+        \seq_gpop_left:NN \g__spath_tmpa_seq \l__spath_tmpb_tl
+
+        \tl_set_eq:Nc \l__spath_tmpc_tl
+        {
+          \tl_use:N \l__spath_prefix_tl
+          \tl_use:N \l__spath_tmpc_tl
+          \tl_use:N \l__spath_suffix_tl
+        }
+        \spath_transform:NVnnnnnn \l__spath_tmpd_tl \l__spath_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+
+        \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
+        {
+          \int_compare:nTF
+          {
+            ##1 == \l__spath_tmpb_tl
+          }
+          {
+            \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpb_tl
+            {
+              \tl_set:Nn \l__spath_tmpb_tl {-1}
+            }
+            \spath_finalpoint:NV \l__spath_tmpe_tl \l__spath_tmpa_tl
+            \spath_initialpoint:Nn \l__spath_tmpf_tl {##2}
+
+            \dim_compare:nTF
+            {
+              \tl_item:Nn \l__spath_tmpe_tl {1}
+              >
+              \tl_item:Nn \l__spath_tmpf_tl {1}
+            }
+            {
+              \spath_splice_between:NVn
+              \l__spath_tmpa_tl
+              \l__spath_tmpd_tl
+              {##2}
+            }
+            {
+              \spath_splice_between:NVn
+              \l__spath_tmpa_tl
+              \l__spath_tmpc_tl
+              {##2}
+            }
+          }
+          {
+            \tl_put_right:Nn \l__spath_tmpa_tl {##2}
+          }
+        }
+        \tl_gset_eq:cN
+        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \l__spath_tmpa_tl
+      }
+      {
+        \msg_warning:nnx
+        { spath3 }
+        { missing soft path }
+        { \tl_use:N \l__spath_tmpc_tl }
+      }
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
   close/.code={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -726,17 +1172,6 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  export~ to~ svg/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    {
-      \spath_export_to_svg:nv {#1}
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
-  },
   transform/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -781,100 +1216,154 @@
   },
   split~ at~ intersections~ with/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
       {
-        \spath_split_path_at_intersections:cv
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        {
+          \spath_split_path_at_intersections: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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ intersections~ with/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      tikz at library@intersections at loaded
+    }
+    {
+    \tl_if_exist:cTF
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
       {
-        \spath_gsplit_path_at_intersections:cv
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        {
+          \spath_gsplit_path_at_intersections: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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ at~ intersections/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      {\tl_use:N \l__spath_prefix_tl #1 \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_if_exist:cTF
         {\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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ intersections/.code~ n~ args={2}{
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
+      tikz at library@intersections at loaded
+    }
+    {
       \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
       {
-        \spath_gsplit_at_intersections:cc
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \tl_if_exist:cTF
         {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        {
+          \spath_gsplit_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}
+        }
+        {
+          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        }
       }
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
       }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ at~ self~ intersections/.code={
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
-      \spath_split_at_self_intersections:c
+      tikz at library@intersections at loaded
+    }
+    {
+      \tl_if_exist:cTF
       {\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}
+      }
+      {
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   split~ globally~ at~ self~ intersections/.code={
     \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
-      \spath_gsplit_at_self_intersections:c
+      tikz at library@intersections at loaded
+    }
+    {
+      \tl_if_exist:cTF
       {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      {
+        \spath_gsplit_at_self_intersections:c
+        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      }
+      {
+        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \msg_warning:nn { spath3 } { load intersections }
     }
   },
   get~ components~ of/.code~ 2~ args={
@@ -966,29 +1455,53 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  insert~ gaps~ after~ components/.code~ n~ args={3}{
+  insert~ gaps~ after~ components/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
       \group_begin:
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
       \seq_gclear:N \g__spath_tmpa_seq
       \seq_gclear:N \g__spath_tmpb_seq
       \spath_numberofcomponents:Nv \l__spath_tmpa_int
       {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \foreach \l__spath_tmpa_tl in {#3}
+
+      \spath_components_to_seq:Nv
+      \l__spath_tmpa_seq
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+
+      \tl_if_empty:NTF \l__spath_tmpd_tl
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
-        \seq_gput_right:Nx
-        \g__spath_tmpb_seq
-        {\int_eval:n
-          {
-            \int_mod:nn { \l__spath_tmpa_tl }{ \l__spath_tmpa_int } + 1
+        \int_step_inline:nnnn {1}{1} { \l__spath_tmpa_int - 1 }
+        {
+          \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          \seq_gput_right:Nx
+          \g__spath_tmpb_seq
+          {\int_eval:n {##1 + 1}}
+        }
+      }
+      {
+        \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+        {
+          \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+          \seq_gput_right:Nx
+          \g__spath_tmpb_seq
+          {\int_eval:n
+            {
+              \int_mod:nn { \l__spath_tmpa_tl }{ \l__spath_tmpa_int } + 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
       {
@@ -995,11 +1508,11 @@
         \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}
+          \spath_shorten_at_end:Nn \l__spath_tmpa_tl {\l__spath_tmpc_tl/2}
         }
         \seq_if_in:NnT \g__spath_tmpb_seq {##1}
         {
-          \spath_shorten_at_start:Nn \l__spath_tmpa_tl {#2/2}
+          \spath_shorten_at_start:Nn \l__spath_tmpa_tl {\l__spath_tmpc_tl/2}
         }
         \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpa_tl
       }
@@ -1014,30 +1527,53 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
-  insert~ gaps~ globally~ after~ components/.code~ n~ args={3}{
+  insert~ gaps~ globally~ after~ components/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
     {
       \group_begin:
+      \tl_if_head_is_group:nTF {#2}
+      {
+        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+      }
+      {
+        \tl_set:Nn \l__spath_tmpc_tl {#2}
+        \tl_clear:N \l__spath_tmpd_tl
+      }
       \seq_gclear:N \g__spath_tmpa_seq
       \seq_gclear:N \g__spath_tmpb_seq
       \spath_numberofcomponents:Nv \l__spath_tmpa_int
       {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \foreach \l__spath_tmpa_tl in {#3}
+
+      \spath_components_to_seq:Nv
+      \l__spath_tmpa_seq
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+
+      \tl_if_empty:NTF \l__spath_tmpd_tl
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
-        \seq_gput_right:Nx
-        \g__spath_tmpb_seq
+        \int_step_inline:nnnn {1}{1} { \l__spath_tmpa_int - 1 }
         {
-          \int_eval:n
-          {
-            \int_mod:nn { \l__spath_tmpa_tl }{ \l__spath_tmpa_int } + 1
+          \seq_gput_right:Nn \g__spath_tmpa_seq {##1}
+          \seq_gput_right:Nx
+          \g__spath_tmpb_seq
+          {\int_eval:n {##1 + 1}}
+        }
+      }
+      {
+        \foreach \l__spath_tmpa_tl in \l__spath_tmpd_tl
+        {
+          \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+          \seq_gput_right:Nx
+          \g__spath_tmpb_seq
+          {\int_eval:n
+            {
+              \int_mod:nn { \l__spath_tmpa_tl }{ \l__spath_tmpa_int } + 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
       {
@@ -1044,11 +1580,11 @@
         \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}
+          \spath_shorten_at_end:Nn \l__spath_tmpa_tl {\l__spath_tmpc_tl/2}
         }
         \seq_if_in:NnT \g__spath_tmpb_seq {##1}
         {
-          \spath_shorten_at_start:Nn \l__spath_tmpa_tl {#2/2}
+          \spath_shorten_at_start:Nn \l__spath_tmpa_tl {\l__spath_tmpc_tl/2}
         }
         \seq_put_right:NV \l__spath_tmpb_seq \l__spath_tmpa_tl
       }
@@ -1135,6 +1671,28 @@
       \msg_warning:nnn { spath3 } { missing soft path } { #1 }
     }
   },
+  replace~ lines/.code={
+    \tl_if_exist:cTF
+    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    {
+      \spath_replace_lines:c
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
+  replace~ lines~ globally/.code={
+    \tl_if_exist:cTF
+    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    {
+      \spath_greplace_lines:c
+      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    }
+    {
+      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+    }
+  },
   remove~ components/.code~ 2~ args={
     \tl_if_exist:cTF
     {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
@@ -1403,7 +1961,10 @@
     }
   }
   {
-    \msg_warning:nnx { spath3 } { missing soft path } { \tl_use:N \l__spath_tmpa_tl }
+    \msg_warning:nnx
+    { spath3 }
+    { missing soft path }
+    { \tl_use:N \l__spath_tmpa_tl }
     \tl_gset_eq:NN \g__spath_smuggle_tl \pgfpointorigin
   }
   \group_end:



More information about the tex-live-commits mailing list.