texlive[64818] Master: spath3 (26oct22)

commits+karl at tug.org commits+karl at tug.org
Wed Oct 26 21:59:14 CEST 2022


Revision: 64818
          http://tug.org/svn/texlive?view=revision&revision=64818
Author:   karl
Date:     2022-10-26 21:59:14 +0200 (Wed, 26 Oct 2022)
Log Message:
-----------
spath3 (26oct22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/spath3/knots.pdf
    trunk/Master/texmf-dist/doc/latex/spath3/knots.tex
    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/tikzlibraryknots.code.tex
    trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex
    trunk/Master/tlpkg/libexec/ctan2tds

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

Modified: trunk/Master/texmf-dist/doc/latex/spath3/knots.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/spath3/knots.tex	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/doc/latex/spath3/knots.tex	2022-10-26 19:59:14 UTC (rev 64818)
@@ -611,6 +611,119 @@
 
 For braids themselves, there is the \Verb+braids+ package which allows input specification in the form of a word in the braid group.
 
+\section{Troubleshooting}
+
+The diagrams drawn by this package can involve quite complicated calculations and they don't always turn out as expected.
+There are plenty of \href{https://tex.stackexchange.com/search?q=knots}{questions on TeX-SX} about this package, but sifting through them can be tricky.
+Through answering some of them, I've developed a few strategies for figuring out what's going on.
+This section details some of what can go wrong and some of those strategies for finding out what's going on. 
+
+\subsection{Small Diagrams}
+
+A common situation when the diagrams don't always work out is when the diagram is relatively small.
+The defaults in this library are set for a diagram of a few centimetres across.
+Some of the key properties are stored as dimensions which means that they don't naturally scale but have to be reset.
+In particular, the \Verb!end tolerance! and \Verb!clip radius! are dimensions with defaults \Verb!14pt! and \Verb!10pt! respectively.
+
+The \Verb!end tolerance! is used to weed out false intersections that occur when a strand is split into pieces.
+Therefore, if the \Verb!consider self intersections! key is not set then \Verb!end tolerance! is largely unneeded (though it is still used) so can safely be set to something very small.
+
+The effect of this can be seen in the following (where to make the issue evident, I've made \Verb!end tolerance! larger rather than make the diagram small).
+
+\begin{example}
+\begin{tikzpicture}
+\begin{knot}[
+  end tolerance=1.5cm
+  ]
+\strand[red] (0,0) to[out=0,in=180] ++(1,1);
+\strand[blue] (0,1) to[out=0,in=180] ++(1,-1);
+\end{knot}
+\begin{knot}
+\strand[red] (1.5,0) to[out=0,in=180] ++(1,1);
+\strand[blue] (1.5,1) to[out=0,in=180] ++(1,-1);
+\end{knot}
+\end{tikzpicture}
+\end{example}
+
+The \Verb!clip radius! determines how much of the diagram is redrawn near a crossing.
+If the crossings are very close together, the redraws can interfere with each other.
+
+\begin{example}
+\begin{tikzpicture}
+\begin{knot}[
+  clip radius=.6cm,
+  flip crossing=2
+  ]
+\strand[red] (0,0) to[out=0,in=180] ++(1,.6) to[out=0,in=180] ++(1,-.6);
+\strand[blue] (0,1) to[out=0,in=180] ++(1,-.6) to[out=0,in=180] ++(1,.6);
+\end{knot}
+\begin{knot}[flip crossing=2]
+\strand[red] (2.5,0) to[out=0,in=180] ++(1,.6) to[out=0,in=180] ++(1,-.6);
+\strand[blue] (2.5,1) to[out=0,in=180] ++(1,-.6) to[out=0,in=180] ++(1,.6);
+\end{knot}
+\end{tikzpicture}
+\end{example}
+
+\subsection{Strategies}
+
+\begin{itemize}
+\item \Verb+draft mode=crossings+
+
+This is useful to check that all the intersections are actually being found.
+Any that aren't might be due to \Verb!end tolerance! being too large.
+Or if \Verb!consider self intersections! is set to \Verb!no splits! then some self intersections might not be found.
+
+\item \Verb+background clip+ and \Verb+clip+ styles.
+
+When a crossing is redrawn, the over strand is clipped to a circle centred on the crossing.
+First a background path is drawn to ``wipe out'' the under strand and then the over strand is drawn.
+The clip circle for the background path is slightly smaller than the over path to avoid an issue whereby faint artefacts are visible (called \href{https://tex.stackexchange.com/q/188447/86}{crop circles} in one question on TeX-SX).
+Rather than use a \Verb!\clip! directly, I use \Verb!\path[background clip]! and \Verb!\path[clip]! which means that these styles can be modified to show the region that is being used.
+A useful style is:
+
+\begin{lstlisting}
+ background clip/.append style={
+    preaction={
+      fill=gray,
+      fill opacity=.5,
+    }
+ }
+\end{lstlisting}
+
+\begin{example}
+\begin{tikzpicture}
+\begin{knot}[
+  clip radius=.6cm,
+  flip crossing=2,
+  background clip/.append style={
+    preaction={
+      fill=gray,
+      fill opacity=.5,
+    }
+  }
+]
+\strand[red] (0,0) to[out=0,in=180] ++(1,.6) to[out=0,in=180] ++(1,-.6);
+\strand[blue] (0,1) to[out=0,in=180] ++(1,-.6) to[out=0,in=180] ++(1,.6);
+\end{knot}
+\begin{knot}[
+  flip crossing=2,
+  background clip/.append style={
+    preaction={
+      fill=gray,
+      fill opacity=.5,
+    }
+  }
+]
+\strand[red] (2.5,0) to[out=0,in=180] ++(1,.6) to[out=0,in=180] ++(1,-.6);
+\strand[blue] (2.5,1) to[out=0,in=180] ++(1,-.6) to[out=0,in=180] ++(1,.6);
+\end{knot}
+\end{tikzpicture}
+\end{example}
+
+
+\end{itemize}
+
+
 \end{document}
 % Local Variables:
 % tex-output-type: "pdf18"

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	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/doc/latex/spath3/spath3.tex	2022-10-26 19:59:14 UTC (rev 64818)
@@ -1,5 +1,5 @@
-%\RequirePackage{shellesc}
-%\immediate\write18{tex spath3_code.dtx}
+\RequirePackage{shellesc}
+\immediate\write18{tex spath3_code.dtx}
 \documentclass{l3doc}
 \usepackage{tikz}
 \usetikzlibrary{
@@ -89,13 +89,63 @@
 \end{lstlisting}
 
 The \texttt{spath3} TikZ library defines a set of keys that can be issued to muck about with soft paths.
-These are all defined in the \texttt{spath} family, so all the following keys should be prefixed by \texttt{spath/}, or the key \texttt{spath/.cd} needs to be used beforehand (but note that as yet I haven't implemented sending unknown keys back to the main \Verb+tikz+ directory).
+These are all defined in the |spath| family, so all the following keys should be prefixed by |spath/|, or the key |spath/.cd| needs to be used beforehand (but note that as yet I haven't implemented sending unknown keys back to the main |tikz| directory).
 
-The keys try to gracefully fail if the path doesn't exist or is empty.
+The keys try to gracefully fail if the path doesn't exist or is empty\footnote{A path that was defined inside a group will be empty if referred to outside that group rather than not existing.}.
 The intention is that the document should still compile with a warning in the log file (and on the console output).
 If this doesn't happen, please report it.
 
+\subsection{Path Names}
 
+Soft paths are stored in macros but are referred to via a name.
+The macro is constructed from the name, but there is scope for a prefix and suffix.
+By default, these are set up so to be compatible with the |intersections| library -- this package and that save their paths in the same underlying macro.
+Some packages that are built on top of this one (such as the |knot| and |penrose| packages) install their own prefixes and suffixes to avoid clashes.
+
+\begin{function}{
+  set prefix,
+  set suffix,
+  prefix,
+  suffix
+}
+\begin{syntax}
+|set prefix=|\marg{prefix}
+|set suffix=|\marg{suffix}
+|prefix=|\oarg{name}
+|suffix=|\oarg{name}
+|set name=|\oarg{name}
+\end{syntax}
+The first two keys set the prefix and suffix directly.
+The other keys allow for defining a label for a prefix and suffix for quick switching between different ones.
+The default (with key |default| or no key specified) is to match the |intersections| library.
+The |knots| library uses this to set a different prefix.
+\end{function}
+
+Using names rather than macros directly also makes it possible to link a soft path with a set of TikZ styles (this is particularly useful when splitting the path into components).
+
+\begin{variable}{current}
+\begin{syntax}
+|\path (0,0) -- (3,0) to[out=90, in=90] (1,0) [spath/adjust and close=current];|
+\end{syntax}
+
+There is a special path name, |current|, which refers to the current path being built.
+To be clear, the test for this name takes place before any prefix or suffix is applied so it depends only on what the user uses.
+
+When this name is encountered, the current path is copied into a macro and that path is used in the command.
+If the command is such that it is possible that the path is modified in some fashion then after the command is finished the old current path is replaced by the new one.
+There are several commands that take multiple paths and |current| can be used in place of any of the paths, but usually there is only one that is modified and so that is the only one that would be used to replace the old current path. 
+
+It only makes sense to use it in a path-building context, and it refers to the path at the moment of invocation, so it doesn't do a lot in the main options on that path but it can be used in options later on in the process.
+
+Sometimes it isn't possible to put commands partway through a path (for example, if the path command is buried in another macro) so there is a key which can be used to delay things to the end of the construction:
+
+\begin{verbatim}
+at end path construction={code}
+\end{verbatim}
+%
+This invokes the |code| right after the path has finished being built.
+\end{variable}
+
 \subsection{Saving and Using Soft Paths}
 
 \begin{function}{save, save global}
@@ -104,16 +154,14 @@
 |save global=|\meta{name}
 \end{syntax}
 
-Saves the current path with name \texttt{<name>}.
+Saves the current path with name \meta{name}.
 This delays until the path is fully constructed so can be issued in the options to the main command.
 
 Soft paths constructed this way are local to the group in which the path command is issued.
 The |global| version saves the path globally which is useful when the original path is inside a scope or even another tikzpicture.
 
-The soft path is actually stored in a macro constructed from the name.
-There are a couple of reasons for using a \emph{name} rather than a macro directly.
-One is so that it is compatible with the \texttt{intersections} library -- by default both this package and that save their paths in the same underlying macro.
-The other is to provide a way to link a soft path with a set of TikZ styles (this is particularly useful when splitting the path into components).
+If wanting to save the border of a node then because there are extra levels of grouping, the global version of this key has to be used.
+
 \end{function}
 
 \begin{function}{clone, clone globally}
@@ -124,8 +172,24 @@
 
 Clones one soft path into another.
 In the second, the clone is global (the original need not be).
+
+By using |current| as the source name, the current soft path in its current state is copied.
+This can be used to get round the restriction whereby |save path| waits until the path is fully constructed before being saved.
 \end{function}
 
+\begin{function}{show, show current path}
+\begin{syntax}
+|show=|\meta{name}
+|show current path|
+\end{syntax}
+
+These keys display a path on the terminal and in the log file.
+They do a bit of sensible line formatting so that the paths are relatively easy to scan through.
+
+The key |show current path| delays the logging until the path is fully constructed.
+To get a view of what the path is at an intermediate stage of construction, use |show=current|.
+\end{function}
+
 \begin{function}{use}
 \begin{syntax}
 |use=|\meta{name}
@@ -145,20 +209,22 @@
 \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.
+The expected use is that when the |weld| key is used then the inserted path starts where the current path ends either because it already does or because the |move| key has also been invoked.
+But there's nothing \emph{stopping} anyone using this key in other circumstances.
 \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}
+See the |transform| key in Section~\ref{sec:transform}.
+\item |use current transformation| applies the current transformation to the inserted path.
+Note that because the keys are processed and then acted upon, this key is always applied \emph{before} the |transform| key.
 \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.
+This means that when re-inserting a soft path back into a high level command (such as |\draw|), existing transformations should have no effect (other than those specified via the |transform| key).
+Where this gets a little tricky is with things like node placement -- 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}.
 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.
-
-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}{
@@ -183,6 +249,19 @@
 \end{itemize}
 \end{function}
 
+\begin{function}{join with}
+\begin{syntax}
+|join with=|\marg{path}\marg{path, options}
+\end{syntax}
+
+This joins the second path to the first, with applying the specified options.
+The options are the same as for the |use| key.
+The first path is modified, the second is not (the second path is copied before any modifications are applied).
+
+It is almost the case that |join with={current}{...}| is synonymous with |use={...}|.
+The difference is that |use={...}| applies an extra check to ensure that the resulting path is not empty.
+\end{function}
+
 \begin{function}{to}
 \begin{syntax}
 |to=|\marg{name}
@@ -198,7 +277,7 @@
 \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.
+They do not render the path, but simply adjust it (but they can be used to modify the current path by invoking with the path name |current|).
 The global versions apply their transformation globally, otherwise it is local to the current group (or scope).
 
 \begin{function}{reverse, reverse global}
@@ -245,9 +324,6 @@
 \subsection{Intersection Routines}
 
 To use these features you need to use the \texttt{intersections} library.
-Note that there is currently an issue with the intersections routine when trying to intersect two parallel (or near parallel) lines.
-One workaround is to replace one of the lines by a B\'ezier curve along the same path.
-The best such replacement is to put the control points at one third and two thirds between the start and end.
 
 \begin{function}{
   split at self intersections,
@@ -346,7 +422,9 @@
 
 \begin{function}{
   insert gaps after components,
-  insert gaps globally after components
+  insert gaps globally after components,
+  insert gaps after segments,
+  insert gaps globally after segments
 }
 \begin{syntax}
 |insert gaps after components=|\marg{path}\marg{gap}\marg{components}
@@ -353,11 +431,18 @@
 |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}
+|insert gaps after segments=|\marg{path}\marg{gap}\marg{segments}
+|insert gaps after segments=|\marg{path}\marg{gap}
+|insert gaps globally after segments=|\marg{path}\marg{gap}\marg{segments}
+|insert gaps globally after segments=|\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.
+
+The \texttt{segments} versions work on the segments of the path rather than its components.
+A \emph{segment} is a minimal drawing piece, meaning a line or B\'ezier curve.
 \end{function}
 
 \begin{function}{
@@ -374,16 +459,20 @@
 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{function}{join components with, join components globally with, join components upright with, join components globally upright with, join components with curve, join components globally with curve}
 \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 with curve=|\marg{path}
+|join components with curve=|\marg{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}
+|join components globally with curve=|\marg{path}
+|join components globally with curve=|\marg{path}\marg{list}
 \end{syntax}
 
 This inserts the |splice path| in the gaps between components of |path| specified by a comma separated list.
@@ -396,6 +485,9 @@
 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.
+
+The |with curve| versions insert a single B\'ezier curve into the gap.
+The curve is chosen to match the tangents of the segments either side of the gap and uses John Hobby's construction of a B\'ezier curve from its tangent directions.
 \end{function}
 
 
@@ -436,18 +528,36 @@
 As with other list routines, the list is parsed via |foreach| first.
 \end{function}
 
+\begin{function}{open, open globally}
+\begin{syntax}
+|open=|\marg{path}
+|open globally=|\marg{path}
+\end{syntax}
 
-\begin{function}{close, close globally, close with, close globally with}
+These open the path by removing all of the closing elements.
+If the closing elements add substantially to the path then they are replaced by a line segment. 
+\end{function}
+
+
+\begin{function}{close, close globally, close with, close globally with, close with curve, close globally with curve, adjust and close, adjust and close globally}
 \begin{syntax}
 |close=|\marg{path}
 |close globally=|\marg{path}
 |close with=|\marg{path}\marg{splice path}
 |close globally with=|\marg{path}\marg{splice path}
+|close with curve=|\marg{path}
+|close globally with curve=|\marg{path}
+|adjust and close=|\marg{path}
+|adjust and close globally=|\marg{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.
+The two |with| variants allow you to specify another path to insert between the end and start of the path.
+The two |with curve| variants insert a B\'ezier curve in the gap; the choice of curve depends on the tangents of the path segments being joined and uses John Hobby's B\'ezier curve construction (as used in the \texttt{hobby} TikZ library).
+The two |adjust| variants shift the end point of the path so that it is at the same place as the start of that component.
+If the last segment is a B\'ezier curve then the second control point is also shifted.
+(The intention with the |adjust| keys is where the start and end of the component are very close together so the adjustment creates a smaller visual effect than adding in a line -- see Example~\ref{ex:close}.) 
 \end{function}
 
 \begin{function}{splice, splice global}
@@ -461,7 +571,7 @@
 \end{function}
 
 
-\subsection{Shortening Paths}
+\subsection{Shortening and Splitting Paths}
 
 \begin{function}{
 shorten at end,
@@ -488,6 +598,42 @@
 If wanting to shorten by a large amount it is better to shorten by a small amount a number of times.
 \end{function}
 
+\begin{function}{
+  split at,
+  split globally at,
+  split at into,
+  split globally at into,
+  split at keep start,
+  split globally at keep start,
+  split at keep end,
+  split globally at keep end,
+  split at keep middle,
+  split globally at keep middle,
+}
+\begin{syntax}
+|split at=|\marg{path}\marg{parameter}
+|split globally at=|\marg{path}\marg{parameter}
+|split at into=|\marg{start path}\marg{end path}\marg{path}\marg{parameter}
+|split globally at into=|\marg{start path}\marg{end path}\marg{path}\marg{parameter}
+|split at keep start=|\marg{path}\marg{parameter}
+|split globally at keep start=|\marg{path}\marg{parameter}
+|split at keep end=|\marg{path}\marg{parameter}
+|split globally at keep end=|\marg{path}\marg{parameter}
+|split at keep middle=|\marg{path}\marg{parameter}\marg{parameter}
+|split globally at keep middle=|\marg{path}\marg{parameter}\marg{parameter}
+\end{syntax}
+
+These keys split a path at a point specified by a parameter.
+The interpretation of the parameter is described in Section~\ref{sec:coordinates}.
+
+The first two keys replace the path with the split path, so this introduces a break at the point specified by the parameter.
+The second two save the split path into a new path.
+
+The ones with \texttt{keep} in the name split a path and keep the designated piece (so throw away the rest).
+The ones that keep the middle need two parameters to specify the break points.
+
+\end{function}
+
 \subsection{Exporting Paths}
 
 There are two keys to export a path.
@@ -516,8 +662,8 @@
   draft mode
 }
 \begin{syntax}
-|knot=|\meta{path}\meta{gap}\meta{components}
-|global knot=|\meta{path}\meta{gap}\meta{components}
+|knot=|\marg{path}\marg{gap}\marg{components}
+|global knot=|\marg{path}\marg{gap}\marg{components}
 \end{syntax}
 
 This style combines various of the above to make it simpler to draw knots and links.
@@ -679,6 +825,24 @@
 \end{tikzpicture}
 \end{example}
 
+\item Closing and adjusting paths.
+\label{ex:close}
+
+\begin{example}
+\begin{tikzpicture}
+\draw[line width=.2cm] (0,0) -- +(1,0) -- +(1,1) -- +(0,1) -- +(.01,.01);
+
+\draw[line width=.2cm] (2,0) -- +(1,0) -- +(1,1) -- +(0,1) -- +(.01,.01)
+-- cycle;
+
+\draw[line width=.2cm] (4,0) -- +(1,0) -- +(1,1) -- +(0,1) -- +(.01,.01)
+[spath/close=current];
+
+\draw[line width=.2cm] (6,0) -- +(1,0) -- +(1,1) -- +(0,1) -- +(.01,.01)
+[spath/adjust and close=current];
+\end{tikzpicture}
+\end{example}
+
 \item Shortening.
 
 \begin{example}
@@ -929,8 +1093,8 @@
 }
 
 % 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];
+%\AtBeginDocument{%
+\tikz[overlay] { \path[spath/save global=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);
@@ -941,5 +1105,8 @@
 \end{tikzpicture}
 \end{example}
 
+The command defining the arc does introduce a box which can introduce additional spacing.
+The syntax above, with the \% at the end of the lines, shouldn't add space but if for some reason it does then more sophisticated solutions to this are detailed at \href{https://tex.stackexchange.com/q/605800/86}{How to save or define a TikZ path for spath3 without introducing artifacts?}.
+
 \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	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/source/latex/spath3/spath3_code.dtx	2022-10-26 19:59:14 UTC (rev 64818)
@@ -143,7 +143,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{8929}
+% \CheckSum{10189}
 %
 % \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
@@ -169,6 +169,8 @@
 % \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.}
+% \changes{2.6}{2021/11/23}{Modified core routines to cope with a "true rectangle" path; added routines for splitting at a parametrised point.}
+% \changes{2.7}{2022/08/24}{Bug fixes}
 %
 % \DoNotIndex{\newcommand,\newenvironment}
 %
@@ -257,7 +259,7 @@
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
 \RequirePackage{pgf}
-\ProvidesExplPackage {spath3} {2021/02/21} {2.4} {Functions for
+\ProvidesExplPackage {spath3} {2022/08/24} {2.7} {Functions for
 manipulating PGF soft paths}
 \RequirePackage{xparse}
 %    \end{macrocode}
@@ -332,6 +334,9 @@
 \fp_new:N \l_@@_tmpa_fp
 \fp_new:N \l_@@_tmpb_fp
 \fp_new:N \l_@@_tmpc_fp
+\fp_new:N \l_@@_tmpd_fp
+\fp_new:N \l_@@_tmpe_fp
+\fp_new:N \l_@@_tmpf_fp
 
 \int_new:N \l_@@_tmpa_int
 \int_new:N \l_@@_tmpb_int
@@ -353,6 +358,23 @@
 \bool_new:N \l_@@_closed_bool
 %    \end{macrocode}
 %
+% True rectangles are rare, but need special handling.
+% They are specified by two tokens, the first specifies the lower left corner which can be handled pretty much as other tokens but the second specifies the width and height meaning that it transforms differently.
+% So when encountering on, the coordinates of the lower left corner are useful to remember.
+%
+%    \begin{macrocode}
+\dim_new:N \l_@@_rectx_dim
+\dim_new:N \l_@@_recty_dim
+
+\bool_new:N \l_@@_rect_bool
+%    \end{macrocode}
+%
+% When restoring a path we need to know whether to update the stored moveto.
+%
+%    \begin{macrocode}
+\bool_new:N \l_spath_movetorelevant_bool
+%    \end{macrocode}
+%
 % The intersection routine can't happen inside a group so we need two token lists to hold the paths that we'll intersect.
 %
 %    \begin{macrocode}
@@ -369,6 +391,8 @@
 \tl_const:Nn \c_spath_curvetoa_tl {\pgfsyssoftpath at curvetosupportatoken}
 \tl_const:Nn \c_spath_curvetob_tl {\pgfsyssoftpath at curvetosupportbtoken}
 \tl_const:Nn \c_spath_closepath_tl {\pgfsyssoftpath at closepathtoken}
+\tl_const:Nn \c_spath_rectcorner_tl {\pgfsyssoftpath at rectcornertoken}
+\tl_const:Nn \c_spath_rectsize_tl {\pgfsyssoftpath at rectsizetoken}
 %    \end{macrocode}
 %
 % We will want to be able to use anonymous spaths internally, so we create a global counter that we can use to refer to them.
@@ -377,6 +401,27 @@
 \int_gzero:N \g_@@_anon_int
 %    \end{macrocode}
 %
+% \begin{macro}[internal]{
+% \spath_anonymous:N,
+% \spath_ganonymous:N
+% }
+% Set the token list to the next anonymous name.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_anonymous:N #1
+{
+  \tl_set:Nx #1 {anonymous_\int_use:N \g_@@_anon_int}
+  \int_gincr:N \g_@@_anon_int
+}
+\cs_new_protected_nopar:Npn \spath_ganonymous:N #1
+{
+  \tl_gset:Nx #1 {anonymous_\int_use:N \g_@@_anon_int}
+  \int_gincr:N \g_@@_anon_int
+}
+\cs_generate_variant:Nn \spath_anonymous:N {c}
+\cs_generate_variant:Nn \spath_ganonymous:N {c}
+%    \end{macrocode}
+% \end{macro}
+%
 % And some error messages
 %    \begin{macrocode}
 \msg_new:nnn { spath3 } { unknown path construction }
@@ -482,6 +527,27 @@
 
       }
 
+      \c_spath_rectcorner_tl
+      {
+        \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_rectcorner_tl
+
+        \tl_put_right:Nx \l_@@_tmpb_tl {{\tl_head:N \l_@@_tmpa_tl}}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \tl_put_right:Nx \l_@@_tmpb_tl {{\tl_head:N \l_@@_tmpa_tl}}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+        \tl_put_right:Nx \l_@@_tmpb_tl {{\tl_head:N \l_@@_tmpa_tl}}
+        \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+        \tl_put_right:Nx \l_@@_tmpb_tl {{\tl_head:N \l_@@_tmpa_tl}}
+        \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+      }
+
       \c_spath_closepath_tl
       {
         \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_moveto_tl
@@ -559,9 +625,11 @@
   \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
   \seq_clear:N \l_@@_tmpa_seq
+  \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+  
   \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
-  \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_moveto_tl
+
   \bool_do_until:nn {
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
@@ -572,6 +640,11 @@
       \seq_put_right:NV \l_@@_tmpa_seq \l_@@_tmpb_tl
       \tl_clear:N \l_@@_tmpb_tl
     }
+    \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+    {
+      \seq_put_right:NV \l_@@_tmpa_seq \l_@@_tmpb_tl
+      \tl_clear:N \l_@@_tmpb_tl
+    }
     \tl_if_single:NTF \l_@@_tmpc_tl
     {
       \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl
@@ -637,7 +710,7 @@
 % \spath_reallength:Nn,
 % \spath_greallength:Nn
 % }
-% The real length of a path is the number of triples that actually draw something (that is, the number of lines, curves, and closepaths).
+% The real length of a path is the number of triples that actually draw something (that is, the number of lines, curves, rectangles, and closepaths).
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \@@_reallength:n #1
 {
@@ -650,6 +723,7 @@
       \c_spath_lineto_tl {}
       \c_spath_curveto_tl {}
       \c_spath_closepath_tl {}
+      \c_spath_rectsize_tl {}
     }
     {
       \int_incr:N \l_@@_tmpa_int
@@ -695,6 +769,10 @@
       {
         \int_incr:N \l_@@_tmpa_int
       }
+      \c_spath_rectcorner_tl
+      {
+        \int_incr:N \l_@@_tmpa_int
+      }
     }
   }
   \int_gzero:N \g_@@_output_int
@@ -765,11 +843,36 @@
   \tl_set:Nn \l_@@_tmpa_tl {#1}
   \tl_reverse:N \l_@@_tmpa_tl
   \tl_clear:N \l_@@_tmpb_tl
-  \tl_set:Nx \l_@@_tmpb_tl
+  \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpa_tl {3}}
+  \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectsize_tl
   {
-    { \tl_item:Nn \l_@@_tmpa_tl {2} }
-    { \tl_item:Nn \l_@@_tmpa_tl {1} }
+    \tl_set:Nx \l_@@_tmpb_tl
+    {
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l_@@_tmpa_tl {2}
+          +
+          \tl_item:Nn \l_@@_tmpa_tl {5}
+        }
+      }
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l_@@_tmpa_tl {1}
+          +
+          \tl_item:Nn \l_@@_tmpa_tl {4}
+        }
+      }
+    }
   }
+  {
+    \tl_set:Nx \l_@@_tmpb_tl
+    {
+      { \tl_item:Nn \l_@@_tmpa_tl {2} }
+      { \tl_item:Nn \l_@@_tmpa_tl {1} }
+    }
+  }
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
   \group_end:
 }
@@ -817,6 +920,16 @@
           { \tl_item:Nn \l_@@_tmpa_tl {3} }
         }
       }
+
+      \c_spath_rectcorner_tl
+      {
+        \tl_set:Nx \l_@@_tmpc_tl
+        {
+          { \tl_item:Nn \l_@@_tmpa_tl {2} }
+          { \tl_item:Nn \l_@@_tmpa_tl {3} }
+        }
+      }
+
     }
     \prg_replicate:nn {3}
     {
@@ -844,119 +957,404 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
-% \spath_reverse:Nn,
-% \spath_greverse:Nn
+% \spath_initialtangent:Nn,
+% \spath_ginitialtangent:Nn
 % }
-% This computes the reverse of the path.
+% The starting tangent of the path.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_reverse:n #1
+\cs_new_protected_nopar:Npn \@@_initialtangent:n #1
 {
   \group_begin:
+  \tl_set:Nx \l_@@_tmpb_tl {\tl_item:nn {#1} {4}}
+  \tl_if_eq:NNTF \l_@@_tmpb_tl \c_spath_curvetoa_tl
+  {
+    \fp_set:Nn \l_@@_tmpa_fp {3}
+  }
+  {
+    \fp_set:Nn \l_@@_tmpa_fp {1}
+  }
+  \tl_clear:N \l_@@_tmpa_tl
+  \tl_set:Nx \l_@@_tmpa_tl
+  {
+    {
+      \fp_to_dim:n {
+        \l_@@_tmpa_fp
+        *
+        (
+        \tl_item:nn {#1} {5}
+        -
+        \tl_item:nn {#1} {2}
+        )
+      }
+    }
+    {
+      \fp_to_dim:n {
+        \l_@@_tmpa_fp
+        *
+        (
+        \tl_item:nn {#1} {6}
+        -
+        \tl_item:nn {#1} {3}
+        )
+      }
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_initialtangent:Nn #1#2
+{
+  \@@_initialtangent:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_initialtangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \spath_ginitialtangent:Nn #1#2
+{
+  \@@_initialtangent:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_ginitialtangent:Nn {NV, cn, cV, Nv}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \spath_finaltangent:Nn,
+% \spath_gfinaltangent:Nn,
+% }
+% The final tangent of the path.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_finaltangent:n #1
+{
+  \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
-
+  \tl_reverse:N \l_@@_tmpa_tl
+  \tl_set:Nx \l_@@_tmpb_tl {\tl_item:nn {#1} {6}}
+  \tl_if_eq:NNTF \l_@@_tmpb_tl \c_spath_curveto_tl
+  {
+    \fp_set:Nn \l_@@_tmpa_fp {3}
+  }
+  {
+    \fp_set:Nn \l_@@_tmpa_fp {1}
+  }
   \tl_clear:N \l_@@_tmpb_tl
-  \tl_clear:N \l_@@_tmpd_tl
-  \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-  \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
-  \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-  \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
-  \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-  
-  \tl_put_left:Nx \l_@@_tmpd_tl
+  \tl_set:Nx \l_@@_tmpb_tl
   {
-    {\dim_use:N \l_@@_tmpa_dim}
-    {\dim_use:N \l_@@_tmpb_dim}
+    {
+      \fp_to_dim:n {
+        \l_@@_tmpa_fp
+        *
+        (
+        \tl_item:Nn \l_@@_tmpa_tl {2}
+        -
+        \tl_item:Nn \l_@@_tmpa_tl {5}
+        )
+      }
+    }
+    {
+      \fp_to_dim:n {
+        \l_@@_tmpa_fp
+        *
+        (
+        \tl_item:Nn \l_@@_tmpa_tl {1}
+        -
+        \tl_item:Nn \l_@@_tmpa_tl {4}
+        )
+      }
+    }
   }
-  
-  \bool_set_false:N \l_@@_closed_bool
-  
-  \bool_until_do:nn {
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_finaltangent:Nn #1#2
+{
+  \@@_finaltangent:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_finaltangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \spath_gfinaltangent:Nn #1#2
+{
+  \@@_finaltangent:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gfinaltangent:Nn {NV, cn, cV, Nv}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]{
+% \spath_finalmovetangent:Nn,
+% \spath_gfinalmovetangent:Nn
+% }
+% Get the last move on the path.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_finalmovetangent:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpc_tl { {0pt} {0pt} }
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \bool_do_until:nn
+  {
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
   {
-    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
-
-    \tl_case:NnTF \l_@@_tmpc_tl
+    \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl}
+    \tl_case:Nn \l_@@_tmpb_tl
     {
-      \c_spath_moveto_tl {
-        
-        \bool_if:NT \l_@@_closed_bool
+      \c_spath_moveto_tl
+      {
+        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:Nn \l_@@_tmpa_tl {4} }
+        \tl_if_eq:NNTF \l_@@_tmpd_tl \c_spath_curveto_tl
         {
-          \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl
-          \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl}
-          \tl_put_right:Nx \l_@@_tmpd_tl
+          \fp_set:Nn \l_@@_tmpa_fp {3}
+        }
+        {
+          \fp_set:Nn \l_@@_tmpa_fp {1}
+        }
+        \tl_set:Nx \l_@@_tmpc_tl
+        {
           {
-            { \tl_head:N \l_@@_tmpd_tl }
-            { \tl_head:N \l_@@_tmpe_tl }
+            \fp_to_dim:n
+            {
+              \l_@@_tmpa_fp
+              *
+              (
+              \tl_item:Nn \l_@@_tmpa_tl {5}
+              -
+              \tl_item:Nn \l_@@_tmpa_tl {2}
+              )
+            }
           }
+          {
+            \fp_to_dim:n
+            {
+              \l_@@_tmpa_fp
+              *
+              (
+              \tl_item:Nn \l_@@_tmpa_tl {6}
+              -
+              \tl_item:Nn \l_@@_tmpa_tl {3}
+              )
+            }
+          }
         }
-        \bool_set_false:N \l_@@_closed_bool
-        \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl
-        \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
-        \tl_clear:N \l_@@_tmpd_tl
       }
-      \c_spath_lineto_tl {
-        \tl_put_left:NV \l_@@_tmpd_tl \c_spath_lineto_tl
-      }
-      \c_spath_curveto_tl {
-        \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetoa_tl
-      }
-      \c_spath_curvetoa_tl {
-        \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curveto_tl
-      }
-      \c_spath_curvetob_tl {
-        \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetob_tl
-      }
     }
+    \prg_replicate:nn {3}
     {
       \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_finalmovetangent:Nn #1#2
+{
+  \@@_finalmovetangent:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_finalmovetangent:Nn {NV, cn, cV}
+\cs_new_protected_nopar:Npn \spath_gfinalmovetangent:Nn #1#2
+{
+  \@@_finalmovetangent:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gfinalmovetangent:Nn {NV, cn, cV}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \spath_reverse:Nn,
+% \spath_greverse:Nn
+% }
+% This computes the reverse of the path.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_reverse:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
 
-      \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
+  \tl_clear:N \l_@@_tmpb_tl
+  \tl_clear:N \l_@@_tmpd_tl
+
+  \bool_set_false:N \l_@@_rect_bool
+
+  \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
+  \bool_while_do:nn {
+    \tl_if_eq_p:NN \l_@@_tmpc_tl \c_spath_rectcorner_tl
+  }
+  {
+    \tl_put_left:Nx \l_@@_tmpd_tl
+    {
+      \tl_item:Nn \l_@@_tmpa_tl {1}
+      {\tl_item:Nn \l_@@_tmpa_tl {2}}
+      {\tl_item:Nn \l_@@_tmpa_tl {3}}
+      \tl_item:Nn \l_@@_tmpa_tl {4}
+      {\tl_item:Nn \l_@@_tmpa_tl {5}}
+      {\tl_item:Nn \l_@@_tmpa_tl {6}}
+    }
+    \prg_replicate:nn {6}
+    {
       \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-      \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
-      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
+    \bool_set_true:N \l_@@_rect_bool
+  }
 
-      \tl_put_left:Nx \l_@@_tmpd_tl
-      {
-        {\dim_use:N \l_@@_tmpa_dim}
-        {\dim_use:N \l_@@_tmpb_dim}
-      }
+  \tl_if_empty:NF \l_@@_tmpa_tl
+  {
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+  
+    \tl_put_left:Nx \l_@@_tmpd_tl
+    {
+      {\dim_use:N \l_@@_tmpa_dim}
+      {\dim_use:N \l_@@_tmpb_dim}
+    }
+  
+    \bool_set_false:N \l_@@_closed_bool
 
+    \bool_until_do:nn {
+      \tl_if_empty_p:N \l_@@_tmpa_tl
     }
     {
-      \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_closepath_tl
+      \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
+      \bool_set_false:N \l_@@_rect_bool
+
+      \tl_case:NnTF \l_@@_tmpc_tl
       {
-        \bool_set_true:N \l_@@_closed_bool
+        \c_spath_moveto_tl {
+        
+          \bool_if:NT \l_@@_closed_bool
+          {
+            \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl
+            \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl}
+            \tl_put_right:Nx \l_@@_tmpd_tl
+            {
+              { \tl_head:N \l_@@_tmpd_tl }
+              { \tl_head:N \l_@@_tmpe_tl }
+            }
+          }
+          \bool_set_false:N \l_@@_closed_bool
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl
+          \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+          \tl_clear:N \l_@@_tmpd_tl
+        }
+        \c_spath_rectcorner_tl {
+
+          \bool_if:NT \l_@@_closed_bool
+          {
+            \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl
+            \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl}
+            \tl_put_right:Nx \l_@@_tmpd_tl
+            {
+              { \tl_head:N \l_@@_tmpd_tl }
+              { \tl_head:N \l_@@_tmpe_tl }
+            }
+          }
+          \bool_set_false:N \l_@@_closed_bool
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl
+          \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+          \tl_clear:N \l_@@_tmpd_tl
+          
+          \bool_while_do:nn {
+            \tl_if_eq_p:NN \l_@@_tmpc_tl \c_spath_rectcorner_tl
+          }
+          {
+            \tl_put_left:Nx \l_@@_tmpb_tl
+            {
+              \tl_item:Nn \l_@@_tmpa_tl {1}
+              {\tl_item:Nn \l_@@_tmpa_tl {2}}
+              {\tl_item:Nn \l_@@_tmpa_tl {3}}
+              \tl_item:Nn \l_@@_tmpa_tl {4}
+              {\tl_item:Nn \l_@@_tmpa_tl {5}}
+              {\tl_item:Nn \l_@@_tmpa_tl {6}}
+            }
+            \prg_replicate:nn {6}
+            {
+              \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+            }
+            \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
+          }
+          \bool_set_true:N \l_@@_rect_bool
+          
+        }
+        \c_spath_lineto_tl {
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_lineto_tl
+        }
+        \c_spath_curveto_tl {
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetoa_tl
+        }
+        \c_spath_curvetoa_tl {
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curveto_tl
+        }
+        \c_spath_curvetob_tl {
+          \tl_put_left:NV \l_@@_tmpd_tl \c_spath_curvetob_tl
+        }
       }
       {
-        \msg_warning:nnx
-        { spath3 }
-        { unknown path construction }
-        {\l_@@_tmpc_tl }
+        \tl_if_empty:NF \l_@@_tmpa_tl
+        {
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+        \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        
+        \tl_put_left:Nx \l_@@_tmpd_tl
+        {
+          {\dim_use:N \l_@@_tmpa_dim}
+          {\dim_use:N \l_@@_tmpb_dim}
+        }
+        }        
       }
+      {
+        \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_closepath_tl
+        {
+          \bool_set_true:N \l_@@_closed_bool
+        }
+        {
+          \msg_warning:nnx
+          { spath3 }
+          { unknown path construction }
+          { \l_@@_tmpc_tl }
+        }
 
-      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+        
+      }
+    }
 
+    \bool_if:NT \l_@@_closed_bool
+    {
+      \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl
+      \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl}
+      \tl_put_right:Nx \l_@@_tmpd_tl
+      {
+        { \tl_head:N \l_@@_tmpd_tl }
+        { \tl_head:N \l_@@_tmpe_tl }
+      }
     }
-  }
 
-  \bool_if:NT \l_@@_closed_bool
-  {
-    \tl_put_right:NV \l_@@_tmpd_tl \c_spath_closepath_tl
-    \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpd_tl}
-    \tl_put_right:Nx \l_@@_tmpd_tl
+    \bool_set_false:N \l_@@_closed_bool
+    \bool_if:NF \l_@@_rect_bool
     {
-      { \tl_head:N \l_@@_tmpd_tl }
-      { \tl_head:N \l_@@_tmpe_tl }
+      \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl
     }
   }
-
-  \bool_set_false:N \l_@@_closed_bool
-  \tl_put_left:NV \l_@@_tmpd_tl \c_spath_moveto_tl
+  
   \tl_put_left:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
-
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
   \group_end:
 }
@@ -997,15 +1395,22 @@
 {
   \group_begin:
   \tl_clear:N \l_@@_tmpa_tl
-  \int_compare:nT
+  \tl_set:Nx \l_@@_tmpb_tl {\tl_head:n {#1}}
+  \tl_if_eq:NNTF \l_@@_tmpb_tl \c_spath_rectcorner_tl
   {
-    \tl_count:n {#1} > 3
+    \tl_set_eq:NN \l_@@_tmpa_tl \c_spath_rectcorner_tl
   }
   {
-    \tl_set:Nx \l_@@_tmpa_tl
+    \int_compare:nT
     {
-      \tl_item:Nn {#1} {4}
+      \tl_count:n {#1} > 3
     }
+    {
+      \tl_set:Nx \l_@@_tmpa_tl
+      {
+        \tl_item:Nn {#1} {4}
+      }
+    }
   }
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
   \group_end:
@@ -1052,6 +1457,10 @@
     {
       \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_curveto_tl
     }
+    \tl_if_eq:NNT \l_@@_tmpb_tl \c_spath_rectsize_tl
+    {
+      \tl_set_eq:NN \l_@@_tmpb_tl \c_spath_rectcorner_tl
+    }
   }
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
   \group_end:
@@ -1083,22 +1492,60 @@
 {
   \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
+
+  \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
   \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
   \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+  \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+  {
+    \dim_set_eq:NN \l_@@_rectx_dim \l_@@_tmpa_dim
+    \dim_set_eq:NN \l_@@_recty_dim \l_@@_tmpb_dim
+  }
   \bool_until_do:nn {
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
   {
+    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-    \dim_set:Nn \l_@@_tmpa_dim
-    {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}}
-    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-    \dim_set:Nn \l_@@_tmpb_dim
-    {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}}
-    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l_@@_tmpa_dim
+      {\dim_min:nn
+        {\tl_head:N \l_@@_tmpa_tl + \l_@@_rectx_dim} {\l_@@_tmpa_dim}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    
+      \dim_set:Nn \l_@@_tmpb_dim
+      {\dim_min:nn
+        {\tl_head:N \l_@@_tmpa_tl + \l_@@_recty_dim} {\l_@@_tmpb_dim}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l_@@_tmpa_dim
+      {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}}
+      \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l_@@_rectx_dim {\tl_head:N \l_@@_tmpa_tl}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    
+      \dim_set:Nn \l_@@_tmpb_dim
+      {\dim_min:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}}
+      \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l_@@_recty_dim {\tl_head:N \l_@@_tmpa_tl}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+    
   }
   \tl_clear:N \l_@@_tmpb_tl
   \tl_put_right:Nx \l_@@_tmpb_tl
@@ -1136,25 +1583,63 @@
 {
   \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
+
+  \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
   \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
   \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
   \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+  \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+  {
+    \dim_set_eq:NN \l_@@_rectx_dim \l_@@_tmpa_dim
+    \dim_set_eq:NN \l_@@_recty_dim \l_@@_tmpb_dim
+  }
   \bool_until_do:nn {
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
   {
+    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-    \dim_set:Nn \l_@@_tmpa_dim
-    {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}}
-    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-    \dim_set:Nn \l_@@_tmpb_dim
-    {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}}
-    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l_@@_tmpa_dim
+      {\dim_max:nn
+        {\tl_head:N \l_@@_tmpa_tl + \l_@@_rectx_dim} {\l_@@_tmpa_dim}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    
+      \dim_set:Nn \l_@@_tmpb_dim
+      {\dim_max:nn
+        {\tl_head:N \l_@@_tmpa_tl + \l_@@_recty_dim} {\l_@@_tmpb_dim}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l_@@_tmpa_dim
+      {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpa_dim}}
+      \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l_@@_rectx_dim {\tl_head:N \l_@@_tmpa_tl}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+
+      \dim_set:Nn \l_@@_tmpb_dim
+      {\dim_max:nn {\tl_head:N \l_@@_tmpa_tl} {\l_@@_tmpb_dim}}
+      \tl_if_eq:NNT \l_@@_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l_@@_recty_dim {\tl_head:N \l_@@_tmpa_tl}
+      }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    }
+    
   }
   \tl_clear:N \l_@@_tmpb_tl
-  \tl_put_right:Nx \l_@@_tmpb_tl
+  \tl_set:Nx \l_@@_tmpb_tl
   {
     {\dim_use:N \l_@@_tmpa_dim}
     {\dim_use:N \l_@@_tmpb_dim}
@@ -1194,7 +1679,7 @@
     \tl_clear:N \l_@@_tmpa_tl
     \tl_put_right:Nn \l_@@_tmpa_tl {
       \ExplSyntaxOn
-      \tl_clear:N #1
+      \tl_clear_new:N #1
       \tl_set:Nn #1 {#2}
       \ExplSyntaxOff
     }
@@ -1212,6 +1697,7 @@
     \spath_save_to_aux:NV #1#1
   }
 }
+\cs_generate_variant:Nn \spath_save_to_aux:N {c}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1241,13 +1727,27 @@
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
   {
+    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
+    
     \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-    
-    \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl + #2}
+
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l_@@_tmpa_dim {\tl_head:N \l_@@_tmpa_tl + #2}
+    }
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
 
-    \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl + #3}
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l_@@_tmpb_dim {\tl_head:N \l_@@_tmpa_tl + #3}
+    }
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
 
     \tl_put_right:Nx \l_@@_tmpb_tl
@@ -1470,6 +1970,8 @@
     \tl_if_empty_p:N \l_@@_tmpa_tl
   }
   {
+    \tl_set:Nx \l_@@_tmpe_tl {\tl_head:N \l_@@_tmpa_tl}
+    
     \tl_put_right:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl}
@@ -1476,11 +1978,21 @@
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpd_tl {\tl_head:N \l_@@_tmpa_tl}
     \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
-
-    \fp_set:Nn \l_@@_tmpa_fp
-    {\l_@@_tmpc_tl * #2 + \l_@@_tmpd_tl * #4 + #6}
-    \fp_set:Nn \l_@@_tmpb_fp
-    {\l_@@_tmpc_tl * #3 + \l_@@_tmpd_tl * #5 + #7}
+    
+    \tl_if_eq:NNTF \l_@@_tmpe_tl \c_spath_rectsize_tl
+    {
+      \fp_set:Nn \l_@@_tmpa_fp
+      {\l_@@_tmpc_tl * #2 + \l_@@_tmpd_tl * #4}
+      \fp_set:Nn \l_@@_tmpb_fp
+      {\l_@@_tmpc_tl * #3 + \l_@@_tmpd_tl * #5}
+    }
+    {
+      \fp_set:Nn \l_@@_tmpa_fp
+      {\l_@@_tmpc_tl * #2 + \l_@@_tmpd_tl * #4 + #6}
+      \fp_set:Nn \l_@@_tmpb_fp
+      {\l_@@_tmpc_tl * #3 + \l_@@_tmpd_tl * #5 + #7}
+    }
+    
     \tl_put_right:Nx \l_@@_tmpb_tl
     {
       {\fp_to_dim:N \l_@@_tmpa_fp}
@@ -1738,8 +2250,8 @@
 \cs_new_protected_nopar:Npn \@@_splice_between:nnn #1#2#3
 {
   \group_begin:
-  \spath_finalpoint:NV \l_@@_tmpd_tl {#1}
-  \spath_initialpoint:NV \l_@@_tmpe_tl {#3}
+  \spath_finalpoint:Nn \l_@@_tmpd_tl {#1}
+  \spath_initialpoint:Nn \l_@@_tmpe_tl {#3}
   \spath_span:NnVV \l_@@_tmpb_tl {#2} \l_@@_tmpd_tl \l_@@_tmpe_tl
   \spath_append_no_move:NnV \l_@@_tmpa_tl {#1} \l_@@_tmpb_tl
   \spath_append_no_move:Nn \l_@@_tmpa_tl {#3}
@@ -1774,6 +2286,340 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
+% \spath_hobby_curve:Nnnnn
+% }
+% Construct the curve from Hobby's algorithm given the start, end, and tangent directions.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_hobby_curve:nnnn #1#2#3#4
+{
+  \group_begin:
+%    \end{macrocode}
+% First tangent vector projected onto vector between endpoints
+%
+% Something a bit weird here as the components are opposite to how I thought they should be ...
+%    \begin{macrocode}
+  \fp_set:Nn \l_@@_tmpa_fp
+  {
+    (
+    (\tl_item:nn {#2} {1})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    +
+    (\tl_item:nn {#2} {2})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+  \fp_set:Nn \l_@@_tmpb_fp
+  {
+    (
+    -
+    (\tl_item:nn {#2} {1})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    +
+    (\tl_item:nn {#2} {2})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+%    \end{macrocode}
+% Second tangent vector projected onto vector between endpoints
+%    \begin{macrocode}
+  \fp_set:Nn \l_@@_tmpc_fp
+  {
+    (
+    (\tl_item:nn {#3} {1})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    +
+    (\tl_item:nn {#3} {2})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+  \fp_set:Nn \l_@@_tmpd_fp
+  {
+    (
+    (\tl_item:nn {#3} {1})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    -
+    (\tl_item:nn {#3} {2})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+
+  \fp_set:Nn \l_@@_tmpe_fp
+  {
+    (
+    2 + sqrt(2) *
+    (\l_@@_tmpb_fp - 1/16 * \l_@@_tmpd_fp)
+    *
+    (\l_@@_tmpd_fp - 1/16 * \l_@@_tmpb_fp)
+    *
+    (\l_@@_tmpa_fp - \l_@@_tmpc_fp)
+    )
+    /
+    (
+    1
+    +
+    (1 - (3 - sqrt(5))/2)
+    *
+    \l_@@_tmpa_fp
+    +
+    (3 - sqrt(5))/2
+    *
+    \l_@@_tmpc_fp
+    )
+    *
+    sqrt
+    (
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    /
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    )
+    /3
+  }
+  \fp_set:Nn \l_@@_tmpf_fp
+  {
+    (
+    2 - sqrt(2) *
+    (\l_@@_tmpb_fp - 1/16 * \l_@@_tmpd_fp)
+    *
+    (\l_@@_tmpd_fp - 1/16 * \l_@@_tmpb_fp)
+    *
+    (\l_@@_tmpa_fp - \l_@@_tmpc_fp)
+    )
+    /
+    (
+    1
+    +
+    (1 - (3 - sqrt(5))/2)
+    *
+    \l_@@_tmpc_fp
+    +
+    (3 - sqrt(5))/2
+    *
+    \l_@@_tmpa_fp
+    )
+    *
+    sqrt
+    (
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    /
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    )
+    /3
+  }
+
+  \tl_set:Nx \l_@@_tmpa_tl
+  {
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#1} {1}
+        +
+        \l_@@_tmpe_fp
+        *
+        (\tl_item:nn {#2} {1})
+      }
+    }
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#1} {2}
+        +
+        \l_@@_tmpe_fp
+        *
+        (\tl_item:nn {#2} {2})
+      }
+    }
+  }
+  \tl_set:Nx \l_@@_tmpb_tl
+  {
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#4} {1}
+        -
+        \l_@@_tmpf_fp
+        *
+        (\tl_item:nn {#3} {1})
+      }
+    }
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#4} {2}
+        -
+        \l_@@_tmpf_fp
+        *
+        (\tl_item:nn {#3} {2})
+      }
+    }
+  }
+
+  \tl_clear:N \l_@@_tmpc_tl
+  \tl_set:NV \l_@@_tmpc_tl \c_spath_moveto_tl
+  \tl_put_right:Nn \l_@@_tmpc_tl {#1}
+  \tl_put_right:NV \l_@@_tmpc_tl \c_spath_curvetoa_tl
+  \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpa_tl
+  \tl_put_right:NV \l_@@_tmpc_tl \c_spath_curvetob_tl
+  \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpb_tl
+  \tl_put_right:NV \l_@@_tmpc_tl \c_spath_curveto_tl
+  \tl_put_right:Nn \l_@@_tmpc_tl {#4}
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_hobby_curve:Nnnnn #1#2#3#4#5
+{
+  \@@_hobby_curve:nnnn {#2}{#3}{#4}{#5}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_hobby_curve:Nnnnn {NVVVV}
+\cs_new_protected_nopar:Npn \spath_ghobby_curve:Nnnnn #1#2#3#4#5
+{
+  \@@_hobby_curve:nnnn {#2}{#3}{#4}{#5}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_ghobby_curve:Nnnnn {NVVVV}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]{
+% \spath_curve_between:Nnn,
+% \spath_curve_between:Nn,
+% \spath_gcurve_between:Nnn,
+% \spath_gcurve_between:Nn
+% }
+% This takes two paths and returns a single path formed by joining the two paths by a curve.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_curve_between:nn #1#2
+{
+  \group_begin:
+  \spath_finalpoint:Nn \l_@@_tmpa_tl {#1}
+  \spath_finaltangent:Nn \l_@@_tmpb_tl {#1}
+  \spath_initialpoint:Nn \l_@@_tmpc_tl {#2}
+  \spath_initialtangent:Nn \l_@@_tmpd_tl {#2}
+
+  \spath_hobby_curve:NVVVV \l_@@_tmpe_tl
+  \l_@@_tmpa_tl \l_@@_tmpb_tl \l_@@_tmpd_tl \l_@@_tmpc_tl
+
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \spath_append_no_move:NV \l_@@_tmpa_tl \l_@@_tmpe_tl
+  \spath_append_no_move:Nn \l_@@_tmpa_tl {#2}
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_curve_between:Nnn #1#2#3
+{
+  \@@_curve_between:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_curve_between:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_curve_between:Nn #1#2
+{
+  \spath_curve_between:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_curve_between:Nn {NV, cn, cv}
+\cs_new_protected_nopar:Npn \spath_gcurve_between:Nnn #1#2#3
+{
+  \@@_curve_between:nn {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gcurve_between:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gcurve_between:Nn #1#2
+{
+  \spath_gcurve_between:NVnn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gcurve_between:Nn {NV, cn, cv}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
 % \spath_close_with:Nn,
 % \spath_gclose_with:Nn
 % }
@@ -1839,6 +2685,77 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
+% \spath_close_with_curve:N,
+% \spath_gclose_with_curve:N
+% }
+% Closes the path with a curve.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_close_with_curve:n #1
+{
+  \group_begin:
+  \spath_finalpoint:Nn \l_@@_tmpa_tl {#1}
+  \spath_finaltangent:Nn \l_@@_tmpb_tl {#1}
+  \spath_finalmovepoint:Nn \l_@@_tmpc_tl {#1}
+  \spath_finalmovetangent:Nn \l_@@_tmpd_tl {#1}
+  \dim_compare:nTF
+  {
+    \dim_abs:n
+    {
+      \tl_item:Nn \l_@@_tmpa_tl {1}
+      -
+      \tl_item:Nn \l_@@_tmpc_tl {1}
+    }
+    +
+    \dim_abs:n
+    {
+      \tl_item:Nn \l_@@_tmpa_tl {2}
+      -
+      \tl_item:Nn \l_@@_tmpc_tl {2}
+    }
+    < 0.01pt
+  }
+  {
+    \@@_close:n {#1}
+  }
+  {
+    
+    \spath_hobby_curve:NVVVV \l_@@_tmpe_tl
+    \l_@@_tmpa_tl \l_@@_tmpb_tl \l_@@_tmpd_tl \l_@@_tmpc_tl
+
+    \tl_set:Nn \l_@@_tmpa_tl {#1}
+    \spath_append_no_move:NV \l_@@_tmpa_tl \l_@@_tmpe_tl
+    \@@_close:V \l_@@_tmpa_tl
+  }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_close_with_curve:Nn #1#2
+{
+  \@@_close_with_curve:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_close_with_curve:Nn {cn, cV, cv, NV}
+\cs_new_protected_nopar:Npn \spath_close_with_curve:N #1
+{
+  \spath_close_with_curve:NV #1#1
+}
+\cs_generate_variant:Nn \spath_close_with_curve:N {c}
+\cs_new_protected_nopar:Npn \spath_gclose_with_curve:Nn #1#2
+{
+  \@@_close_with_curve:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gclose_with_curve:Nn {cn, cV, cv, NV}
+\cs_new_protected_nopar:Npn \spath_gclose_with_curve:N #1
+{
+  \spath_gclose_with_curve:NV #1#1
+}
+\cs_generate_variant:Nn \spath_gclose_with_curve:N {c}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
 % \spath_weld:Nnn,
 % \spath_weld:Nn,
 % \spath_gweld:Nnn,
@@ -1893,7 +2810,7 @@
 % \spath_gappend_no_move:Nn,
 % }
 % Append the path from the second \Verb+spath+ to the first, removing
-% the adjoining move.
+% the adjoining move if neither path has a rectangle either side of the join or if the first path isn't closed.
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \@@_append_no_move:nn #1#2
 {
@@ -1900,9 +2817,20 @@
   \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
   \tl_set:Nn \l_@@_tmpb_tl {#2}
-  \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
-  \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
-  \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
+  \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpb_tl}
+  \spath_finalaction:Nn \l_@@_tmpd_tl {#1}
+  \bool_if:nT {
+    ! \tl_if_eq_p:NN \l_@@_tmpd_tl \c_spath_closepath_tl
+    &&
+    ! \tl_if_eq_p:NN \l_@@_tmpd_tl \c_spath_rectcorner_tl
+    &&
+    \tl_if_eq_p:NN \l_@@_tmpc_tl \c_spath_moveto_tl
+  }
+  {
+    \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
+    \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
+    \tl_set:Nx \l_@@_tmpb_tl {\tl_tail:N \l_@@_tmpb_tl}
+  }
   
   \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
@@ -2079,6 +3007,56 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
+% \spath_bake_shorten:Nn,
+% \spath_bake_shorten:N,
+% \spath_gbake_shorten:Nn,
+% \spath_gbake_shorten:N
+% }
+%
+% The shortening routine is applied quite late in the process of building a soft path so this ensures that it is done.
+% 
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_bake_shorten:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \pgfsyssoftpath at getcurrentpath\l_@@_tmpb_tl
+  \pgfsyssoftpath at setcurrentpath\l_@@_tmpa_tl
+  \pgf at prepare@end at of@path
+  \pgf at prepare@start at of@path
+  \pgfsyssoftpath at getcurrentpath\l_@@_tmpa_tl
+  \pgfsyssoftpath at setcurrentpath\l_@@_tmpb_tl
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_bake_shorten:Nn #1#2
+{
+  \@@_bake_shorten:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_bake_shorten:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_bake_shorten:N #1
+{
+  \spath_bake_shorten:NV #1#1
+}
+\cs_generate_variant:Nn \spath_bake_shorten:N {c}
+\cs_new_protected_nopar:Npn \spath_gbake_shorten:Nn #1#2
+{
+  \@@_bake_shorten:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gbake_shorten:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_gbake_shorten:N #1
+{
+  \spath_gbake_shorten:NV #1#1
+}
+\cs_generate_variant:Nn \spath_gbake_shorten:N {c}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
 % \spath_close:Nn,
 % \spath_close:N,
 % \spath_gclose:Nn,
@@ -2124,7 +3102,92 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{
+% \spath_adjust_close:Nn,
+% \spath_adjust_close:N,
+% \spath_adjust_gclose:Nn,
+% \spath_adjust_gclose:N
+% }
+% This closes a path and adjusts the end point to be where the final move point (so where the close points to) is.
+% The intention is that this should be used if the two points are visually the same point but mathematically different.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_adjust_close:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \spath_finalmovepoint:NV \l_@@_tmpb_tl \l_@@_tmpa_tl
+  \spath_finalpoint:NV \l_@@_tmpc_tl \l_@@_tmpa_tl
+  \tl_reverse:N \l_@@_tmpa_tl
+  \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+  \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+  \tl_set:Nx \l_@@_tmpd_tl {\tl_head:N \l_@@_tmpa_tl}
+  \tl_if_eq:NNT \l_@@_tmpd_tl \c_spath_curveto_tl
+  {
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    \tl_clear:N \l_@@_tmpe_tl
+    \tl_set:Nx \l_@@_tmpe_tl {
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l_@@_tmpa_tl {1}
+          -
+          \tl_item:Nn \l_@@_tmpc_tl {2}
+          +
+          \tl_item:Nn \l_@@_tmpb_tl {2}
+        }
+      }
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l_@@_tmpa_tl {2}
+          -
+          \tl_item:Nn \l_@@_tmpc_tl {1}
+          +
+          \tl_item:Nn \l_@@_tmpb_tl {1}
+        }
+      }
+    }
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+    \tl_put_left:NV \l_@@_tmpa_tl \l_@@_tmpe_tl
+    \tl_put_left:NV \l_@@_tmpa_tl \l_@@_tmpd_tl
+  }
+  \tl_reverse:N \l_@@_tmpa_tl
+  \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl
+  \tl_put_right:NV \l_@@_tmpa_tl \c_spath_closepath_tl
+  \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \@@_adjust_close:n {V}
+\cs_new_protected_nopar:Npn \spath_adjust_close:Nn #1#2
+{
+  \@@_adjust_close:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_adjust_close:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_adjust_close:N #1
+{
+  \spath_adjust_close:NV #1#1
+}
+\cs_generate_variant:Nn \spath_adjust_close:N {c}
+\cs_new_protected_nopar:Npn \spath_adjust_gclose:Nn #1#2
+{
+  \@@_adjust_close:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_adjust_gclose:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_adjust_gclose:N #1
+{
+  \spath_adjust_gclose:NV #1#1
+}
+\cs_generate_variant:Nn \spath_adjust_gclose:N {c}
+%    \end{macrocode}
+% \end{macro}
 %
+%
 % \begin{macro}[internal]{
 % \spath_open:Nn,
 % \spath_open:N,
@@ -2132,11 +3195,12 @@
 % \spath_gopen:N
 % }
 % Removes all close paths from the path, replacing them by \Verb+lineto+ if they move any distance.
+% Rectangles are replaced by lines with the start/end at the lower left corner.
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \@@_open:n #1
 {
   \group_begin:
-  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \spath_replace_rectangles:Nn \l_@@_tmpa_tl {#1}
   \tl_clear:N \l_@@_tmpb_tl
   \bool_until_do:nn {
     \tl_if_empty_p:N \l_@@_tmpa_tl
@@ -2210,6 +3274,7 @@
   \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
   \group_end:
 }
+\cs_generate_variant:Nn \@@_open:n {V}
 \cs_new_protected_nopar:Npn \spath_open:Nn #1#2
 {
   \@@_open:n {#2}
@@ -2232,6 +3297,8 @@
 {
   \spath_gopen:NV #1#1
 }
+\cs_generate_variant:Nn \spath_open:N {c}
+\cs_generate_variant:Nn \spath_gopen:N {c}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2358,6 +3425,126 @@
 % \end{macro}
 %
 % \begin{macro}[internal]{
+% \spath_replace_rectangles:Nn,
+% \spath_replace_rectangles:Nn,
+% \spath_replace_rectangles:Nn,
+% \spath_replace_rectangles:Nn,
+% }
+% Replace any rectangle components by lines.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_replace_rectangles:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \tl_clear:N \l_@@_tmpb_tl
+
+  \bool_do_until:nn
+  {
+    \tl_if_empty_p:N \l_@@_tmpa_tl
+  }
+  {
+    \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl }
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+    \tl_set:Nx \l_@@_tmpd_tl {\tl_head:N \l_@@_tmpa_tl }
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+    \tl_set:Nx \l_@@_tmpe_tl {\tl_head:N \l_@@_tmpa_tl }
+    \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+
+    \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_rectcorner_tl
+    {
+
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+      \dim_set:Nn \l_@@_tmpa_dim
+      {
+        \tl_item:Nn \l_@@_tmpa_tl {1}
+      }
+      \dim_set:Nn \l_@@_tmpb_dim
+      {
+        \tl_item:Nn \l_@@_tmpa_tl {2}
+      }
+      
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+      \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl }
+      
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_moveto_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 \c_spath_lineto_tl
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l_@@_tmpd_tl + \l_@@_tmpa_dim }
+        }
+      }
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_lineto_tl
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l_@@_tmpd_tl + \l_@@_tmpa_dim }
+        }
+      }
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l_@@_tmpe_tl + \l_@@_tmpb_dim }
+        }
+      }
+
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_lineto_tl
+      \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+      \tl_put_right:Nx \l_@@_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l_@@_tmpe_tl + \l_@@_tmpb_dim }
+        }
+      }
+
+      \tl_put_right:NV \l_@@_tmpb_tl \c_spath_closepath_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
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \@@_replace_rectangles:n {V}
+\cs_new_protected_nopar:Npn \spath_replace_rectangles:Nn #1#2
+{
+  \@@_replace_rectangles:n {#2}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_replace_rectangles:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_replace_rectangles:N #1
+{
+  \spath_replace_rectangles:NV #1#1
+}
+\cs_generate_variant:Nn \spath_replace_rectangles:N {c}
+\cs_new_protected_nopar:Npn \spath_greplace_rectangles:Nn #1#2
+{
+  \@@_replace_rectangles:n {#2}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_greplace_rectangles:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_greplace_rectangles:N #1
+{
+  \spath_greplace_rectangles:NV #1#1
+}
+\cs_generate_variant:Nn \spath_greplace_rectangles:N {c}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
 % \spath_remove_empty_components:Nn,
 % \spath_remove_empty_components:N,
 % \spath_gremove_empty_components:Nn,
@@ -2688,9 +3875,11 @@
   }
   {
     \fp_set:Nn \l_@@_tmpa_fp {.5 * \l_@@_tmpa_fp / \l_@@_tmpb_fp}
-    \fp_compare:nTF
+    \bool_if:nTF
     {
-      0 < \l_@@_tmpa_fp && \l_@@_tmpa_fp < 1
+      \fp_compare_p:n {0 < \l_@@_tmpa_fp}
+      && 
+      \fp_compare_p:n {\l_@@_tmpa_fp < 1}
     }
     {
       \@@_split_curve:nV {#1} \l_@@_tmpa_fp
@@ -2908,16 +4097,74 @@
 %    \end{macrocode}
 % \end{macro}
 %
+%
 % \begin{macro}[internal]{
+% \spath_split_rectangle:Nnn,
+% \spath_gsplit_rectangle:Nnn
+% }
+% Cuts a rectangle at a point.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_split_rectangle:nn #1#2
+{
+  \group_begin:
+  \spath_open:Nn \l_@@_tmpa_tl {#1}
+  \fp_set:Nn \l_@@_tmpa_fp {4*(#2)}
+  \spath_split_at:NNVV
+  \l_@@_tmpa_tl \l_@@_tmpb_tl \l_@@_tmpa_tl \l_@@_tmpa_fp
+  \@@_append_no_move:VV \l_@@_tmpb_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_split_rectangle:Nnn #1#2#3
+{
+  \@@_split_rectangle:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_rectangle:Nnn {NnV, NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gsplit_rectangle:Nnn #1#2#3
+{
+  \@@_split_rectangle:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_rectangle:Nnn {NnV, NVn, NVV}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]{
 % \spath_split_at:NNnn,
 % \spath_split_at:Nnn,
 % \spath_split_at:Nn,
 % \spath_gsplit_at:NNnn
 % \spath_gsplit_at:Nnn,
-% \spath_gsplit_at:Nn
+% \spath_gsplit_at:Nn,
+% \spath_split_at_keep_start:Nnn,
+% \spath_split_at_keep_start:Nn,
+% \spath_gsplit_at_keep_start:Nnn,
+% \spath_gsplit_at_keep_start:Nn,
+% \spath_split_at_keep_end:Nnn,
+% \spath_split_at_keep_end:Nn,
+% \spath_gsplit_at_keep_end:Nnn,
+% \spath_gsplit_at_keep_end:Nn,
+% \spath_split_at_normalised:NNnn,
+% \spath_split_at_normalised:Nnn,
+% \spath_split_at_normalised:Nn,
+% \spath_gsplit_at_normalised:NNnn
+% \spath_gsplit_at_normalised:Nnn,
+% \spath_gsplit_at_normalised:Nn,
+% \spath_split_at_normalised_keep_start:Nnn,
+% \spath_split_at_normalised_keep_start:Nn,
+% \spath_gsplit_at_normalised_keep_start:Nnn,
+% \spath_gsplit_at_normalised_keep_start:Nn,
+% \spath_split_at_normalised_keep_end:Nnn,
+% \spath_split_at_normalised_keep_end:Nn,
+% \spath_gsplit_at_normalised_keep_end:Nnn,
+% \spath_gsplit_at_normalised_keep_end:Nn,
 % }
 % Split a path according to the parameter generated by the intersection routine.
 % The versions with two \texttt{N} arguments stores the two parts in two macros, the version with a single \texttt{N} joins them back into a single path (as separate components).
+% The \texttt{keep} versions throw away the other part of the curve.
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \@@_split_at:nn #1#2
 {
@@ -2948,11 +4195,28 @@
   \bool_set_true:N \l_@@_tmpa_bool
 
   \tl_set:Nn \l_@@_tmpe_tl {#1}
-  \tl_clear:N \l_@@_tmpc_tl
 
   \dim_zero:N \l_@@_tmpa_dim
   \dim_zero:N \l_@@_tmpb_dim
 
+  % Remember if the component is closed
+  \spath_finalaction:NV \l_@@_tmpa_tl \l_@@_tmpe_tl
+
+  \bool_set:Nn \l_@@_closed_bool
+  {
+    \tl_if_eq_p:NN \l_@@_tmpa_tl \c_spath_closepath_tl
+    ||
+    \tl_if_eq_p:NN \l_@@_tmpa_tl \c_spath_rectcorner_tl
+  }
+  
+  % Open it
+  \spath_open:N \l_@@_tmpe_tl
+
+  \tl_clear:N \l_@@_tmpa_tl
+  \tl_clear:N \l_@@_tmpb_tl
+  \tl_clear:N \l_@@_tmpc_tl
+  \tl_clear:N \l_@@_tmpd_tl
+  
   \bool_until_do:nn {
     \tl_if_empty_p:N \l_@@_tmpe_tl
     ||
@@ -2971,6 +4235,10 @@
       {
         \int_incr:N \l_@@_tmpb_int
       }
+      \c_spath_rectcorner_tl
+      {
+        \int_incr:N \l_@@_tmpb_int
+      }
     }
     \int_compare:nT { \l_@@_tmpb_int < \l_@@_tmpa_int  }
     {
@@ -3075,14 +4343,65 @@
         \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpa_tl
         \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
       }
+      
+      \c_spath_rectcorner_tl
+      {
+        \tl_clear:N \l_@@_tmpd_tl
+        \tl_put_right:NV \l_@@_tmpd_tl \l_@@_tmpf_tl
+        
+        \tl_put_right:Nx \l_@@_tmpd_tl {{\tl_head:N \l_@@_tmpe_tl}}
+        \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpe_tl}
+        \tl_put_right:Nx \l_@@_tmpd_tl {{\tl_head:N \l_@@_tmpe_tl}}
+        \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpe_tl}
+
+        \tl_put_right:Nx \l_@@_tmpd_tl {\tl_head:N \l_@@_tmpe_tl}
+        \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpe_tl}
+
+        \tl_put_right:Nx \l_@@_tmpd_tl {{\tl_head:N \l_@@_tmpe_tl}}
+        \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpe_tl}
+        \tl_put_right:Nx \l_@@_tmpd_tl {{\tl_head:N \l_@@_tmpe_tl}}
+        \tl_set:Nx \l_@@_tmpe_tl {\tl_tail:N \l_@@_tmpe_tl}
+
+        \spath_split_rectangle:NVV
+        \l_@@_tmpa_tl
+        \l_@@_tmpd_tl
+        \l_@@_tmpa_fp
+
+        \tl_put_right:NV \l_@@_tmpc_tl \l_@@_tmpa_tl
+        \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+      }
+
     }
   }
 
+  \bool_if:NT \l_@@_closed_bool
+  {
+    \prg_replicate:nn {3}
+    {
+      \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl}
+    }
+    \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl
+    \tl_set_eq:NN \l_@@_tmpc_tl \l_@@_tmpb_tl
+    \tl_clear:N \l_@@_tmpb_tl
+  }
+  
   \tl_gclear:N \g_@@_output_tl
   \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpc_tl
   \@@_tl_gput_right_braced:NV \g_@@_output_tl \l_@@_tmpb_tl
   \group_end:
 }
+\cs_generate_variant:Nn  \@@_split_at:nn {nV, VV}
+\cs_new_protected_nopar:Npn \@@_split_at_normalised:nn #1#2
+{
+  \group_begin:
+  \spath_reallength:Nn \l_@@_tmpa_int {#1}
+      
+  \tl_set:Nx \l_@@_tmpa_tl
+  {\fp_to_decimal:n {(#2) * (\l_@@_tmpa_int)}}
+  \@@_split_at:nV {#1} \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_generate_variant:Nn  \@@_split_at_normalised:nn {nV}
 \cs_new_protected_nopar:Npn \spath_split_at:NNnn #1#2#3#4
 {
   \@@_split_at:nn {#3}{#4}
@@ -3099,6 +4418,114 @@
   \tl_gclear:N \g_@@_output_tl
 }
 \cs_generate_variant:Nn \spath_gsplit_at:NNnn {NNVn, NNVV, NNnV}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_start:Nnn #1#2#3
+{
+  \@@_split_at:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_start:Nn #1#2
+{
+  \spath_split_at_keep_start:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_start:Nnn #1#2#3
+{
+  \@@_split_at:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_start:Nn #1#2
+{
+  \spath_gsplit_at_keep_start:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_end:Nnn #1#2#3
+{
+  \@@_split_at:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_end:Nn #1#2
+{
+  \spath_split_at_keep_end:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_end:Nnn #1#2#3
+{
+  \@@_split_at:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_end:Nn #1#2
+{
+  \spath_gsplit_at_keep_end:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:NNnn #1#2#3#4
+{
+  \@@_split_at_normalised:nn {#3}{#4}
+  \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_set:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:NNnn {NNVn, NNVV, NNnV, ccvn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:NNnn #1#2#3#4
+{
+  \@@_split_at_normalised:nn {#3}{#4}
+  \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_gset:Nx #2 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:NNnn {NNVn, NNVV, NNnV, ccvn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_start:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_start:Nn #1#2
+{
+  \spath_split_at_normalised_keep_start:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_start:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_start:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {1}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_start:Nn #1#2
+{
+  \spath_gsplit_at_normalised_keep_start:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_start:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_end:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_end:Nn #1#2
+{
+  \spath_split_at_normalised_keep_end:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_end:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_end:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g_@@_output_tl {2}}
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_end:Nn #1#2
+{
+  \spath_gsplit_at_normalised_keep_end:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_end:Nn {cn}
 %    \end{macrocode}
 %
 % 
@@ -3133,6 +4560,38 @@
 {
   \spath_gsplit_at:NVn #1#1{#2}
 }
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1
+  {
+    \tl_item:Nn \g_@@_output_tl {1}
+    \tl_item:Nn \g_@@_output_tl {2}
+  }
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:Nn #1#2
+{
+  \spath_split_at_normalised:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:Nnn #1#2#3
+{
+  \@@_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1
+  {
+    \tl_item:Nn \g_@@_output_tl {1}
+    \tl_item:Nn \g_@@_output_tl {2}
+  }
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:Nn #1#2
+{
+  \spath_gsplit_at_normalised:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:Nn {cn}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -3473,7 +4932,41 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{
+% \spath_shorten_at_both_ends:Nnn,
+% \spath_shorten_at_both_ends:Nn,
+% \spath_gshorten_at_both_ends:Nnn,
+% \spath_gshorten_at_both_ends:Nn
+% }
+% 
+% This macro shortens a path from the start by a dimension.
 %
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \spath_shorten_at_both_ends:Nnn #1#2#3
+{
+  \spath_shorten_at_start:Nnn #1{#2}{#3}
+  \spath_shorten_at_end:Nnn #1{#2}{#3}
+}
+\cs_new_protected_nopar:Npn \spath_shorten_at_both_ends:Nn #1#2
+{
+  \spath_shorten_at_start:Nn #1{#2}
+  \spath_shorten_at_end:Nn #1{#2}
+}
+\cs_generate_variant:Nn \spath_shorten_at_both_ends:Nn {cn, cV, NV}
+\cs_new_protected_nopar:Npn \spath_gshorten_at_both_ends:Nnn #1#2#3
+{
+  \spath_gshorten_at_start:Nnn #1{#2}{#3}
+  \spath_gshorten_at_end:Nnn #1{#2}{#3}
+}
+\cs_new_protected_nopar:Npn \spath_gshorten_at_both_ends:Nn #1#2
+{
+  \spath_gshorten_at_start:Nn #1{#2}
+  \spath_gshorten_at_end:Nn #1{#2}
+}
+\cs_generate_variant:Nn \spath_gshorten_at_both_ends:Nn {cn, cV, NV}
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{Points on a Path}
 %
 % \begin{macro}[internal]{
@@ -3561,6 +5054,95 @@
           }
         }
 
+        \c_spath_rectsize_tl
+        {
+          \fp_compare:nTF
+          {
+            \l_@@_tmpa_fp <= .25
+          }
+          {
+            \tl_set:Nx \l_@@_tmpc_tl
+            {
+              {\fp_to_dim:n
+                {
+                  ( \tl_item:Nn \l_@@_tmpa_tl {2} )
+                  +
+                  4 * \l_@@_tmpa_fp * ( \tl_item:Nn \l_@@_tmpa_tl {5} )
+                }
+              }
+              {\fp_to_dim:n {\tl_item:Nn \l_@@_tmpa_tl {3} } }
+            }
+          }
+          {
+            \fp_compare:nTF
+            {
+              \l_@@_tmpa_fp <= .5
+            }
+            {
+              \tl_set:Nx \l_@@_tmpc_tl
+              {
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l_@@_tmpa_tl {2} )
+                    +
+                    ( \tl_item:Nn \l_@@_tmpa_tl {5} )
+                  }
+                }
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l_@@_tmpa_tl {3} )
+                    +
+                    (4 * (\l_@@_tmpa_fp) - 1) * ( \tl_item:Nn \l_@@_tmpa_tl {6} )
+                  }
+                }
+              }
+            }
+            {
+              \fp_compare:nTF
+              {
+                \l_@@_tmpa_fp <= .75
+              }
+              {
+                \tl_set:Nx \l_@@_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l_@@_tmpa_tl {2} )
+                      +
+                      (3 - 4 * (\l_@@_tmpa_fp)) *( \tl_item:Nn \l_@@_tmpa_tl {5} )
+                    }
+                  }
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l_@@_tmpa_tl {3} )
+                      +
+                      ( \tl_item:Nn \l_@@_tmpa_tl {6} )
+                    }
+                  }
+                }
+                
+              }
+              {
+                \tl_set:Nx \l_@@_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l_@@_tmpa_tl {2} )
+                    }
+                  }
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l_@@_tmpa_tl {3} )
+                      +
+                      (4 - 4 *(\l_@@_tmpa_fp)) * ( \tl_item:Nn \l_@@_tmpa_tl {6} )
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
         \c_spath_closepath_tl
         {
           \tl_set:Nx \l_@@_tmpc_tl
@@ -3717,6 +5299,71 @@
           }
         }
 
+        \c_spath_rectsize_tl
+        {
+          \fp_compare:nTF
+          {
+            \l_@@_tmpa_fp <= .25
+          }
+          {
+            \tl_set:Nx \l_@@_tmpc_tl
+            {
+              {\fp_to_dim:n
+                {
+                  \tl_item:Nn \l_@@_tmpa_tl {5}
+                }
+              }
+              {0pt}
+            }
+          }
+          {
+            \fp_compare:nTF
+            {
+              \l_@@_tmpa_fp <= .5
+            }
+            {
+              \tl_set:Nx \l_@@_tmpc_tl
+              {
+                {0pt}
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l_@@_tmpa_tl {6} )
+                  }
+                }
+              }
+            }
+            {
+              \fp_compare:nTF
+              {
+                \l_@@_tmpa_fp <= .75
+              }
+              {
+                \tl_set:Nx \l_@@_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      -( \tl_item:Nn \l_@@_tmpa_tl {5} )
+                    }
+                  }
+                  {0pt}
+                }
+                
+              }
+              {
+                \tl_set:Nx \l_@@_tmpc_tl
+                {
+                  {0pt}
+                  {\fp_to_dim:n
+                    {
+                      - ( \tl_item:Nn \l_@@_tmpa_tl {6} )
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
         \c_spath_closepath_tl
         {
           \tl_set:Nx \l_@@_tmpc_tl
@@ -3898,19 +5545,21 @@
   \tl_set:Nn \l_@@_tmpb_tl {#1}
   \tl_set:Nn \l_@@_tmpc_tl {#2}
 
-  \spath_reallength:Nn \l_@@_tmpa_int {#1}
-  
   % Remember if the component is closed
   \spath_finalaction:NV \l_@@_tmpa_tl \l_@@_tmpb_tl
-  
+
   \bool_set:Nn \l_@@_closed_bool
   {
     \tl_if_eq_p:NN \l_@@_tmpa_tl \c_spath_closepath_tl
+    ||
+    \tl_if_eq_p:NN \l_@@_tmpa_tl \c_spath_rectcorner_tl
   }
-
+  
   % Open it
   \spath_open:N \l_@@_tmpb_tl
 
+  \spath_reallength:NV \l_@@_tmpa_int \l_@@_tmpb_tl
+  
   % Sort intersections along the component
   \pgfintersectionsortbyfirstpath
   \spath_intersect:NN \l_@@_tmpb_tl \l_@@_tmpc_tl
@@ -3933,6 +5582,7 @@
     {
       \bool_set_false:N \l_@@_closed_bool
     }
+
     \seq_get_right:NN \l_@@_tmpb_seq \l_@@_tmpa_tl
     \fp_compare:nT
     {
@@ -3941,7 +5591,6 @@
     {
       \bool_set_false:N \l_@@_closed_bool
     }
-
     
     \tl_set:Nn \l_@@_tmpg_tl {-1}
 
@@ -3989,6 +5638,7 @@
     \tl_set_eq:NN \l_@@_tmpb_tl \l_@@_tmpe_tl
   }
 
+  
   \bool_if:NT \l_@@_closed_bool
   {
     \spath_join_component:Nn \l_@@_tmpb_tl {1}
@@ -4847,6 +6497,7 @@
 {
   \pgfsyssoftpath at getcurrentpath #1
 }
+\cs_generate_variant:Nn \spath_get_current_path:N {c}
 %    \end{macrocode}
 %
 %    \begin{macrocode}
@@ -4855,6 +6506,7 @@
   \pgfsyssoftpath at getcurrentpath #1
   \tl_gset_eq:NN #1 #1
 }
+\cs_generate_variant:Nn \spath_gget_current_path:N {c}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -4912,10 +6564,13 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2
 {
-  \path[#1] \pgfextra{
-    \spath_set_current_path:n {#2}
-    \tl_put_right:Nn \tikz at preactions {\def\tikz at actions@path{#2}}
-  };
+  \tl_if_empty:nF {#2}
+  {
+    \path[#1] \pgfextra{
+      \spath_set_current_path:n {#2}
+      \tl_put_left:Nn \tikz at preactions {\def\tikz at actions@path{#2}}
+    };
+  }
 }
 \cs_generate_variant:Nn \spath_tikz_path:nn {Vn, VV, nv, Vv, nV}
 %    \end{macrocode}
@@ -4929,8 +6584,8 @@
   \spath_finalpoint:Nn \l_@@_tmpa_tl {#1}
   \tl_set:Nx \l_@@_tmpa_tl
   {
-    \exp_not:c {pgf at x}=\tl_item:Nn \l_@@_tmpa_tl {1}
-    \exp_not:c {pgf at y}=\tl_item:Nn \l_@@_tmpa_tl {2}
+    \exp_not:c {pgf at x}=\tl_item:Nn \l_@@_tmpa_tl {1} \relax
+    \exp_not:c {pgf at y}=\tl_item:Nn \l_@@_tmpa_tl {2} \relax
   }
   \use:c {pgf at process}{%
     \tl_use:N \l_@@_tmpa_tl
@@ -4939,20 +6594,23 @@
   }
   \tl_set:Nx \l_@@_tmpa_tl
   {
-    \exp_not:c {tikz at lastx}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lasty}=\exp_not:c {pgf at y}
-    \exp_not:c {tikz at lastxsaved}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lastysaved}=\exp_not:c {pgf at y}
+    \exp_not:c {tikz at lastx}=\exp_not:c {pgf at x} \relax
+    \exp_not:c {tikz at lasty}=\exp_not:c {pgf at y} \relax
+    \exp_not:c {tikz at lastxsaved}=\exp_not:c {pgf at x} \relax
+    \exp_not:c {tikz at lastysaved}=\exp_not:c {pgf at y} \relax
   }
   \tl_use:N \l_@@_tmpa_tl
   \spath_finalmovepoint:Nn \l_@@_tmpa_tl {#1}
-  \ifpgfsyssoftpathmovetorelevant%
-  \tl_gset_eq:cN {pgfsyssoftpath at lastmoveto} \l_@@_tmpa_tl
-  \fi
+  \bool_if:NT \l_spath_movetorelevant_bool
+  {
+    \ifpgfsyssoftpathmovetorelevant%
+    \tl_gset_eq:cN {pgfsyssoftpath at lastmoveto} \l_@@_tmpa_tl
+    \fi
+  }
   \tl_set:Nx \l_@@_tmpa_tl
   {
-    \exp_not:c {pgf at x}=\tl_item:Nn \l_@@_tmpa_tl {1}
-    \exp_not:c {pgf at y}=\tl_item:Nn \l_@@_tmpa_tl {2}
+    \exp_not:c {pgf at x}=\tl_item:Nn \l_@@_tmpa_tl {1} \relax
+    \exp_not:c {pgf at y}=\tl_item:Nn \l_@@_tmpa_tl {2} \relax
   }
   \use:c {pgf at process}{%
     \tl_use:N \l_@@_tmpa_tl
@@ -4959,12 +6617,18 @@
     \pgftransforminvert
     \use:c {pgf at pos@transform at glob}
   }
-  \tl_set:Nx \l_@@_tmpa_tl
+  \bool_if:NT \l_spath_movetorelevant_bool
   {
-    \exp_not:c {tikz at lastmovetox}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lastmovetoy}=\exp_not:c {pgf at y}
+    \dim_if_exist:cT {tikz at lastmovetox}
+    {
+      \tl_set:Nx \l_@@_tmpa_tl
+      {
+        \exp_not:c {tikz at lastmovetox}=\exp_not:c {pgf at x} \relax
+        \exp_not:c {tikz at lastmovetoy}=\exp_not:c {pgf at y} \relax
+      }
+      \tl_use:N \l_@@_tmpa_tl
+    }
   }
-  \tl_use:N \l_@@_tmpa_tl
   \tl_clear_new:c {tikz at timer}
   \tl_set:cn {tikz at timer}
   {
@@ -5028,6 +6692,11 @@
 %<*tikzspath3>
 % \fi
 %
+%    \begin{macrocode}
+%<@@=tikzspath>
+%    \end{macrocode}
+%
+%
 % This provides an interface to the soft path manipulation routines via a series of TikZ keys.
 % They all live in the \texttt{spath} family.
 %
@@ -5037,13 +6706,30 @@
 \RequirePackage{expl3}
 \ExplSyntaxOn
 
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
+\tl_new:N \l_@@_tmpc_tl
+\tl_new:N \l_@@_tmpd_tl
+\tl_new:N \l_@@_tmpe_tl
+\tl_new:N \l_@@_tmpf_tl
+
+\int_new:N \l_@@_tmpa_int
+\seq_new:N \l_@@_tmpa_seq
+\seq_new:N \l_@@_tmpb_seq
+\seq_new:N \l_@@_tmpc_seq
+\seq_new:N \l_@@_tmpd_seq
+
 \tl_new:N \l_@@_current_tl
 \tl_new:N \l_@@_reverse_tl
 \tl_new:N \l_@@_prefix_tl
 \tl_new:N \l_@@_suffix_tl
 \tl_new:N \g_@@_smuggle_tl
+\tl_new:N \g_@@_output_tl
+\tl_new:N \l_@@_check_tl
+\clist_new:N \g_@@_output_clist
 \seq_new:N \g_@@_tmpa_seq
 \seq_new:N \g_@@_tmpb_seq
+\seq_new:N \g_@@_output_seq
 \bool_new:N \l_@@_draft_bool
 %    \end{macrocode}
 %
@@ -5050,11 +6736,14 @@
 % We surround all the keys with checks to ensure that the soft path under consideration does actually exist, but if it doesn't we should warn the user.
 %
 %    \begin{macrocode}
-\msg_new:nnn { spath3 } { missing soft path } { Soft~ path~ #1~ doesn't~ exist }
-\msg_new:nnnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty}
+\msg_new:nnn { spath3 } { missing soft path }
+{ Soft~ path~ #1~ doesn't~ exist~ \msg_line_context:}
+\msg_new:nnnn { spath3 } { empty soft path }
+{ Soft~ path~ #1~ is~ empty~ \msg_line_context:}
 {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 }
+{ 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.
@@ -5065,9 +6754,14 @@
 %    \end{macrocode}
 %
 % When a soft path is grabbed from TikZ we're usually deep in a group so I've adapted the code from the intersections library to dig the definition out of the group without making everything global.
-% 
+%
+% Interestingly, the intersections library doesn't clear its naming code once it is used meaning that it keeps resetting the definition of a path back to its original one every time a path command is called.
+%
+% Also, when the hook is restored outside a scope then no check is made to ensure that the inner one was actually invoked.
+% This can cause issues when the syntax \Verb!\tikz .. ;! is used since the end of the path coincides with the end of the picture.
 %    \begin{macrocode}
 \tl_new:N \g_@@_tikzfinish_tl
+\tl_new:N \l_@@_tikzfinish_outside_tl
 \cs_new_protected_nopar:Npn \spath_at_end_of_path:
 {
   \tl_use:N \g_@@_tikzfinish_tl
@@ -5075,8 +6769,43 @@
 }
 \tl_put_right:Nn \tikz at finish {\spath_at_end_of_path:}
 
+\tikzset{
+  every~ scope/.append~ style={
+    execute~ at~ begin~ scope={
+      \tl_set_eq:NN \l_@@_tikzfinish_outside_tl \g_@@_tikzfinish_tl
+    },
+    execute~ at~ end~ scope={
+      \tl_use:N \g_@@_tikzfinish_tl
+      \tl_gclear:N \g_@@_tikzfinish_tl
+      \tl_gset_eq:NN \g_@@_tikzfinish_tl \l_@@_tikzfinish_outside_tl
+    },
+  },
+}
+%    \end{macrocode}
+%
+% This is for delaying something until the path is fully constructed (but no later), sometimes useful to be able to specify this in the path options rather than directly at the end of the path.
+%
+%    \begin{macrocode}
+\tl_new:N \l_@@_tikzpath_finish_tl
+
+\cs_new_protected_nopar:Npn \@@_at_end_of_path_construction:
+{
+  \tl_use:N \l_@@_tikzpath_finish_tl
+  \tl_clear:N \l_@@_tikzpath_finish_tl
+}
+
+\tl_put_left:Nn \tikz at finish {\@@_at_end_of_path_construction:}
+%    \end{macrocode}
+%
+% Code for saving a path
+%
+%    \begin{macrocode}
 \cs_new_protected_nopar:Npn \spath_save_path:Nn #1#2
 {
+  \tl_if_empty:NF \g_@@_tikzfinish_tl
+  {
+    \tl_use:N \g_@@_tikzfinish_tl
+  }
   \tl_gput_right:Nn \g_@@_tikzfinish_tl
   {
     \tl_clear_new:N #1
@@ -5127,6 +6856,228 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{
+% \@@_check_path:nnn
+% \@@_check_two_paths:nnnn
+% \@@_check_three_paths:nnnnn
+% }
+% Given a path name as the second argument, check if it exists and is not empty, and if so reinsert it after the first argument.
+% The third argument is code to be executed in case of a missing or empty path.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_check_path:nnn #1#2#3
+{
+  \tl_set:Nn \l_@@_check_tl {#3}
+  \tl_if_exist:cTF {\@@_path_name:n {#2}}
+  {
+    \tl_if_empty:cTF {\@@_path_name:n {#2}}
+    {
+      \msg_warning:nnn { spath3 } { empty soft path } { #2 }
+    }
+    {
+      \tl_set:Nn \l_@@_check_tl {
+        #1 {\@@_path_name:n {#2}}
+      }
+    }
+  }
+  {
+    \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+  }
+  \tl_use:N \l_@@_check_tl
+}
+\cs_new_protected_nopar:Npn \@@_check_two_paths:nnnn #1#2#3#4
+{
+  \@@_check_path:nnn {
+    \@@_check_path:nnn {#1}{#2}{#4}
+  }{#3}{#4}
+}
+\cs_new_protected_nopar:Npn \@@_check_three_paths:nnnnn #1#2#3#4#5
+{
+  \@@_check_path:nnn {
+    \@@_check_path:nnn {
+      \@@_check_path:nnn {#1}{#2}{#5}
+    }{#3}{#5}
+  }{#4}{#5}
+}
+\cs_generate_variant:Nn \@@_check_path:nnn {nVn}
+\cs_generate_variant:Nn \@@_check_two_paths:nnnn {nnVn}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \@@_maybe_current_path:nn
+% \@@_maybe_current_path_reuse:nnn
+% \@@_maybe_current_two_paths_reuse_both:nnnn
+% \@@_maybe_current_two_paths_reuse_first:nnnn
+% \@@_maybe_current_two_paths_reuse_second:nnnn
+% }
+% If the named path is ``current'' then get the current path and use that.
+% The second version puts the resulting path back as the current path.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_maybe_current_path:nn #1#2
+{
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#2}}
+  }
+  #1 {#2}
+}
+\cs_new_protected_nopar:Npn \@@_maybe_current_path_reuse:nnn #1#2#3
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#2}}
+  }
+  #1 {#2} #3
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\@@_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\@@_path_name:n {#2}}
+      \spath_set_tikz_data:v {\@@_path_name:n {#2}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \@@_maybe_current_two_paths_reuse_both:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\@@_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\@@_path_name:n {#2}}
+      \spath_set_tikz_data:v {\@@_path_name:n {#2}}
+    }
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \tl_if_empty:cF {\@@_path_name:n {#3}}
+    {
+      \spath_set_current_path:c {\@@_path_name:n {#3}}
+      \spath_set_tikz_data:v {\@@_path_name:n {#3}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \@@_maybe_current_two_paths_reuse_first:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\@@_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\@@_path_name:n {#2}}
+      \spath_set_tikz_data:v {\@@_path_name:n {#2}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \@@_maybe_current_two_paths_reuse_second:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\@@_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \tl_if_empty:cF {\@@_path_name:n {#3}}
+    {
+      \spath_set_current_path:c {\@@_path_name:n {#3}}
+      \spath_set_tikz_data:v {\@@_path_name:n {#3}}
+    }
+  }
+}
+\cs_generate_variant:Nn \@@_maybe_current_path:nn {nV}
+\cs_generate_variant:Nn \@@_maybe_current_path_reuse:nnn {nVn}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{
+% \@@_seq_from_foreach:NNn
+% }
+%
+% Convert a PGF foreach list, as the third argument, to a sequence.
+% The second argument is the maximum number on the list.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_seq_from_foreach:Nnn #1#2#3
+{
+  \group_begin:
+  \seq_gclear:N \g_@@_output_seq
+
+  \tl_if_empty:nTF {#3}
+  {
+    \int_step_inline:nnnn {1}{1} {#2}
+    {
+      \seq_gput_right:Nn \g_@@_output_seq {##1}
+    }
+  }
+  {
+    \foreach \l_@@_tmpa_tl in {#3}
+    {
+      \int_compare:nTF { \l_@@_tmpa_tl > 0 }
+      {
+        \seq_gput_right:NV \g_@@_output_seq \l_@@_tmpa_tl
+      }
+      {
+        \seq_gput_right:Nx \g_@@_output_seq
+        {\int_eval:n {#2 - \l_@@_tmpa_tl}}
+      }
+    }
+    \seq_gsort:Nn \g_@@_output_seq
+    {
+      \int_compare:nNnTF {##1} < {##2}
+      { \sort_return_same: }
+      { \sort_return_swapped: }
+    }
+  }
+  \group_end:
+  \seq_set_eq:NN #1 \g_@@_output_seq
+  \seq_gclear:N \g_@@_output_seq
+}
+\cs_generate_variant:Nn \@@_seq_from_foreach:Nnn {NVV, NVn}
+%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \@@_path_name:n
+% }
+% Wrap the argument in the prefix and suffix to generate the proper name.
+%    \begin{macrocode}
+\cs_new:Npn \@@_path_name:n #1
+{
+  \tl_use:N \l_@@_prefix_tl
+  #1
+  \tl_use:N \l_@@_suffix_tl
+}
+\cs_generate_variant:Nn \@@_path_name:n {V}
+%    \end{macrocode}
+% \end{macro}
+%
 % When joining two paths we provide a set of options for how to process the second path.
 %
 %    \begin{macrocode}
@@ -5134,6 +7085,7 @@
 \bool_new:N \l_@@_weld_bool
 \bool_new:N \l_@@_move_bool
 \bool_new:N \l_@@_global_bool
+\bool_new:N \l_@@_current_transformation_bool
 \tl_new:N \l_@@_joinpath_tl
 \tl_new:N \l_@@_transformation_tl
 
@@ -5176,6 +7128,10 @@
     \@@_set_bool:Nn \l_@@_global_bool {#1}
   },
   global/.default = true,
+  use~ current~ transformation/.code={
+    \@@_set_bool:Nn \l_@@_current_transformation_bool {#1}
+  },
+  use~ current~ transformation/.default = true,
   transform/.store~in=\l_@@_transformation_tl,
   .unknown/.code = {
     \tl_set_eq:NN \l_@@_joinpath_tl \pgfkeyscurrentname
@@ -5191,6 +7147,766 @@
 \cs_set_eq:NN \getComponentOf \clist_item:Nn
 %    \end{macrocode}
 %
+% \subsection{Helper Functions}
+%
+% \begin{macro}[internal]{
+% \@@_use_path:n
+% }
+% Use a path, possibly manipulating it first.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_use_path:n #1
+{
+  \tl_set:Nn \l_@@_joinpath_tl {#1}
+  \spath_get_current_path:N \l_@@_current_tl
+      
+  \bool_if:NT \l_@@_reverse_bool
+  {
+    \spath_reverse:N \l_@@_joinpath_tl
+  }
+
+  \bool_if:NT \l_@@_current_transformation_bool
+  {
+    \pgfgettransform \l_@@_tmpa_tl
+    \spath_transform:NV
+    \l_@@_joinpath_tl
+    \l_@@_tmpa_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}
+      \spath_numberofcomponents:NV \l_@@_tmpa_int \l_@@_joinpath_tl
+      \int_compare:nT {\l_@@_tmpa_int == 1}
+      {
+        \bool_set_false:N \l_spath_movetorelevant_bool
+      }
+    }
+    \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
+}
+\cs_generate_variant:Nn \@@_use_path:n {V, v}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]{
+% \@@_join_with:nn
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_join_with:Nn #1#2
+{
+  \tl_set:Nn \l_@@_joinpath_tl {#2}
+  
+  \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
+    #1
+    \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 {:NV}
+
+  \cs_if_exist:cF {\tl_use:N \l_@@_tmpa_tl}
+  {
+    \tl_show:N \l_@@_tmpa_tl
+  }
+
+  \use:c {\tl_use:N \l_@@_tmpa_tl } #1
+  \l_@@_joinpath_tl
+}
+\cs_generate_variant:Nn \@@_join_with:Nn {cv, cn}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_join_components_with:Nnn
+% \@@_join_components_upright_with:Nnn
+% }
+% Join the specified components of the first path by splicing in the second.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_join_components_with_aux:nnn #1#2#3
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpc_tl {#1}
+  \tl_if_empty:nT {#3}
+  {
+    \spath_spot_weld_components:N \l_@@_tmpc_tl
+  }
+
+  \spath_numberofcomponents:NV \l_@@_tmpa_int \l_@@_tmpc_tl
+  \@@_seq_from_foreach:NVn \l_@@_tmpb_seq \l_@@_tmpa_int {#3}
+
+  \spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpc_tl
+  
+  \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+  \seq_pop_left:NN \l_@@_tmpb_seq \l_@@_tmpb_tl
+
+  \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+  {
+    \int_compare:nTF
+    {
+      ##1 == \l_@@_tmpb_tl
+    }
+    {
+      \seq_pop_left:NNF \l_@@_tmpb_seq \l_@@_tmpb_tl
+      {
+        \tl_set:Nn \l_@@_tmpb_tl {-1}
+      }
+      \spath_splice_between:Nnn \l_@@_tmpa_tl {#2} {##2}
+    }
+    {
+      \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_join_components_with:Nnnn #1#2#3#4
+{
+  \@@_join_components_with_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_join_components_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_join_components_with:Nnn #1#2#3
+{
+  \@@_join_components_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_join_components_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_with:Nnnn #1#2#3#4
+{
+  \@@_join_components_with_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_gjoin_components_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_with:Nnn #1#2#3
+{
+  \@@_gjoin_components_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_gjoin_components_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \@@_join_components_upright_with_aux:nnn #1#2#3
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpc_tl {#1}
+  \tl_if_empty:nT {#3}
+  {
+    \spath_spot_weld_components:N \l_@@_tmpc_tl
+  }
+
+  \spath_numberofcomponents:NV \l_@@_tmpa_int \l_@@_tmpc_tl
+  \@@_seq_from_foreach:NVn \l_@@_tmpb_seq \l_@@_tmpa_int {#3}
+
+  \spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpc_tl
+  
+  \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+  \seq_pop_left:NN \l_@@_tmpb_seq \l_@@_tmpb_tl
+
+  \tl_set:Nn \l_@@_tmpc_tl {#2}
+  \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_pop_left:NNF \l_@@_tmpb_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:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_join_components_upright_with:Nnnn #1#2#3#4
+{
+  \@@_join_components_upright_with_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_join_components_upright_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_join_components_upright_with:Nnn #1#2#3
+{
+  \@@_join_components_upright_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_join_components_upright_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_upright_with:Nnnn #1#2#3#4
+{
+  \@@_join_components_upright_with_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_gjoin_components_upright_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_upright_with:Nnn #1#2#3
+{
+  \@@_gjoin_components_upright_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_gjoin_components_upright_with:Nnn {cvV}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{
+% \@@_get_components:Nn
+% }
+% Get the components of the named path to the token list.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_get_components_aux:n #1
+{
+  \clist_gclear_new:N \g_@@_output_clist
+  \spath_components_to_seq:Nn \l_@@_tmpa_seq {#1}
+  
+  \seq_map_inline:Nn \l_@@_tmpa_seq
+  {
+    \spath_anonymous:N \l_@@_tmpa_tl
+    \tl_new:c {\@@_path_name:V \l_@@_tmpa_tl}
+    \tl_set:cn {\@@_path_name:V \l_@@_tmpa_tl} {##1}
+    \clist_gput_right:NV \g_@@_output_clist \l_@@_tmpa_tl
+  }
+}
+\cs_new_protected_nopar:Npn \@@_get_components:Nn #1#2
+{
+  \clist_clear_new:N #1
+  \@@_get_components_aux:n {#2}
+  \clist_set_eq:NN #1 \g_@@_output_clist
+  \clist_gclear:N \g_@@_output_clist
+}
+\cs_generate_variant:Nn \@@_get_components:Nn {NV, Nv}
+\cs_new_protected_nopar:Npn \@@_gget_components:Nn #1#2
+{
+  \clist_gclear_new:N #1
+  \@@_get_components_aux:n {#2}
+  \clist_gset_eq:NN #1 \g_@@_output_clist
+  \clist_gclear:N \g_@@_output_clist
+}
+\cs_generate_variant:Nn \@@_gget_components:Nn {NV, Nv}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{
+% \@@_render_components:n
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_render_components:nn #1#2
+{
+  \group_begin:
+  \spath_components_to_seq:Nn \l_@@_tmpa_seq {#2}
+  \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+  {
+    \spath_tikz_path:nn
+    {
+      every~ spath~ component/.try,
+      spath ~component~ ##1/.try,
+      spath ~component/.try={##1},
+      every~ #1~ component/.try,
+      #1 ~component~ ##1/.try,
+      #1 ~component/.try={##1},
+    }
+    {
+      ##2
+    }
+  }
+  \group_end:
+}
+\cs_generate_variant:Nn \@@_render_components:nn {nv}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \@@_insert_gaps_after_components:nn
+% }
+%
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_components_aux:nnn #1#2#3
+{
+  \group_begin:
+  \spath_numberofcomponents:Nn \l_@@_tmpa_int {#1}
+  \@@_seq_from_foreach:NVn \l_@@_tmpa_seq \l_@@_tmpa_int {#3}
+
+  \tl_if_empty:nT {#3}
+  {
+    \seq_pop_right:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+  }
+
+  \seq_clear:N \l_@@_tmpb_seq
+  \seq_map_inline:Nn \l_@@_tmpa_seq {
+    \seq_put_right:Nx
+    \l_@@_tmpb_seq
+    {\int_eval:n
+      {
+        \int_mod:nn { ##1 }{ \l_@@_tmpa_int } + 1
+      }
+    }
+  }
+
+  \spath_components_to_seq:Nn \l_@@_tmpc_seq {#1}
+
+  \seq_clear:N \l_@@_tmpd_seq
+  \seq_map_indexed_inline:Nn \l_@@_tmpc_seq
+  {
+    \tl_set:Nn \l_@@_tmpa_tl {##2}
+    \seq_if_in:NnT \l_@@_tmpa_seq {##1}
+    {
+      \spath_shorten_at_end:Nn \l_@@_tmpa_tl {(#2)/2}
+    }
+    \seq_if_in:NnT \l_@@_tmpb_seq {##1}
+    {
+      \spath_shorten_at_start:Nn \l_@@_tmpa_tl {(#2)/2}
+    }
+    \seq_put_right:NV \l_@@_tmpd_seq \l_@@_tmpa_tl
+  }
+  \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpd_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_components:Nnnn #1#2#3#4
+{
+  \@@_insert_gaps_after_components_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_insert_gaps_after_components:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_components:Nnn #1#2#3
+{
+  \@@_insert_gaps_after_components:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_insert_gaps_after_components:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \@@_ginsert_gaps_after_components:Nnnn #1#2#3#4
+{
+  \@@_insert_gaps_after_components_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_ginsert_gaps_after_components:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_ginsert_gaps_after_components:Nnn #1#2#3
+{
+  \@@_ginsert_gaps_after_components:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_ginsert_gaps_after_components:Nnn {cnn, cVV}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_insert_gaps_after_segments:Nn
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_segments_aux:nnn #1#2#3
+{
+  \group_begin:
+  \spath_reallength:Nn \l_@@_tmpa_int {#1}
+  \@@_seq_from_foreach:NVn \l_@@_tmpa_seq \l_@@_tmpa_int {#3}
+
+  \tl_if_empty:nT {#3}
+  {
+    \seq_pop_right:NN \l_@@_tmpb_seq \l_@@_tmpa_tl
+  }
+
+  \seq_clear:N \l_@@_tmpb_seq
+  \seq_map_inline:Nn \l_@@_tmpa_seq {
+    \seq_put_right:Nx
+    \l_@@_tmpb_seq
+    {\int_eval:n
+      {
+        \int_mod:nn { ##1 }{ \l_@@_tmpa_int } + 1
+      }
+    }
+  }
+
+  \spath_segments_to_seq:Nn \l_@@_tmpc_seq {#1}
+
+  \seq_clear:N \l_@@_tmpd_seq
+  \seq_map_indexed_inline:Nn \l_@@_tmpc_seq
+  {
+    \tl_set:Nn \l_@@_tmpa_tl {##2}
+    \seq_if_in:NnT \l_@@_tmpa_seq {##1}
+    {
+      \spath_shorten_at_end:Nn \l_@@_tmpa_tl {(#2)/2}
+    }
+    \seq_if_in:NnT \l_@@_tmpb_seq {##1}
+    {
+      \spath_shorten_at_start:Nn \l_@@_tmpa_tl {(#2)/2}
+    }
+    \seq_put_right:NV \l_@@_tmpd_seq \l_@@_tmpa_tl
+  }
+  \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpd_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_segments:Nnnn #1#2#3#4
+{
+  \@@_insert_gaps_after_segments_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_insert_gaps_after_segments:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_insert_gaps_after_segments:Nnn #1#2#3
+{
+  \@@_insert_gaps_after_segments:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_insert_gaps_after_segments:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \@@_ginsert_gaps_after_segments:Nnnn #1#2#3#4
+{
+  \@@_insert_gaps_after_segments_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_ginsert_gaps_after_segments:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \@@_ginsert_gaps_after_segments:Nnn #1#2#3
+{
+  \@@_ginsert_gaps_after_segments:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \@@_ginsert_gaps_after_segments:Nnn {cnn, cVV}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_join_components:Nn
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_join_components_aux:nn #1#2
+{
+  \group_begin:
+
+  \tl_set:Nn \l_@@_tmpa_tl {#1}
+  \spath_numberofcomponents:NV \l_@@_tmpa_int \l_@@_tmpa_tl
+  \@@_seq_from_foreach:NVn \l_@@_tmpa_seq \l_@@_tmpa_int {#2}
+
+  \seq_reverse:N \l_@@_tmpa_seq
+  
+  \seq_map_inline:Nn \l_@@_tmpa_seq
+  {
+    \spath_join_component:Nn \l_@@_tmpa_tl {##1}
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_join_components:Nnn #1#2#3
+{
+  \@@_join_components_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_join_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_join_components:Nn #1#2
+{
+  \@@_join_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_join_components:Nn {cn}
+\cs_new_protected_nopar:Npn \@@_gjoin_components:Nnn #1#2#3
+{
+  \@@_join_components_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_gjoin_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_gjoin_components:Nn #1#2
+{
+  \@@_gjoin_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_gjoin_components:Nn {cn}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_join_components_with_bezier:Nn
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_join_components_with_bezier_aux:nn #1#2
+{
+  \group_begin:
+  \tl_set:Nn \l_@@_tmpc_tl {#1}
+  \tl_if_empty:nT {#2}
+  {
+    \spath_spot_weld_components:N \l_@@_tmpc_tl
+  }
+
+  \spath_numberofcomponents:NV \l_@@_tmpa_int \l_@@_tmpc_tl
+  \@@_seq_from_foreach:NVn \l_@@_tmpb_seq \l_@@_tmpa_int {#2}
+
+  \spath_components_to_seq:NV \l_@@_tmpa_seq \l_@@_tmpc_tl
+  
+  \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+  \seq_pop_left:NN \l_@@_tmpb_seq \l_@@_tmpb_tl
+
+  \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+  {
+    \int_compare:nTF
+    {
+      ##1 == \l_@@_tmpb_tl
+    }
+    {
+      \seq_pop_left:NNF \l_@@_tmpb_seq \l_@@_tmpb_tl
+      {
+        \tl_set:Nn \l_@@_tmpb_tl {-1}
+      }
+      \spath_curve_between:Nn \l_@@_tmpa_tl {##2}
+    }
+    {
+      \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+    }
+  }
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_join_components_with_bezier:Nnn #1#2#3
+{
+  \@@_join_components_with_bezier_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_join_components_with_bezier:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_join_components_with_bezier:Nn #1#2
+{
+  \@@_join_components_with_bezier:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_join_components_with_bezier:Nn {cV}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_with_bezier:Nnn #1#2#3
+{
+  \@@_join_components_with_bezier_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_gjoin_components_with_bezier:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_gjoin_components_with_bezier:Nn #1#2
+{
+  \@@_gjoin_components_with_bezier:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_gjoin_components_with_bezier:Nn {cV}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
+% \@@_remove_components:nn
+% }
+%
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_remove_components_aux:nn #1#2
+{
+  \group_begin:
+
+  \spath_numberofcomponents:Nn \l_@@_tmpa_int {#1}
+  \@@_seq_from_foreach:NVn \l_@@_tmpa_seq \l_@@_tmpa_int {#2}
+
+  \spath_components_to_seq:Nn \l_@@_tmpb_seq {#1}
+  
+  \seq_pop_left:NNF \l_@@_tmpa_seq \l_@@_tmpa_tl
+  {
+    \tl_clear:N \l_@@_tmpa_tl
+  }
+  
+  \seq_clear:N \l_@@_tmpc_seq
+  \seq_map_indexed_inline:Nn \l_@@_tmpb_seq
+  {
+    \tl_set:Nn \l_@@_tmpb_tl {##1}
+    \tl_if_eq:NNTF \l_@@_tmpb_tl \l_@@_tmpa_tl
+    {
+      \seq_pop_left:NNF \l_@@_tmpa_seq \l_@@_tmpa_tl
+      {
+        \tl_clear:N \l_@@_tmpa_tl
+      }
+    }
+    {
+      \seq_put_right:Nn \l_@@_tmpc_seq {##2}
+    }
+  }
+
+  \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpc_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_remove_components:Nnn #1#2#3
+{
+  \@@_remove_components_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_remove_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_remove_components:Nn #1#2
+{
+  \@@_remove_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_remove_components:Nn {cn}
+\cs_new_protected_nopar:Npn \@@_gremove_components:Nnn #1#2#3
+{
+  \@@_remove_components_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_gremove_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \@@_gremove_components:Nn #1#2
+{
+  \@@_gremove_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \@@_gremove_components:Nn {cn}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]{
+% \@@_transform_to:nn,
+% \@@_transform_upright_to:nn
+% }
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_transform_to_aux:nn #1#2
+{
+  \group_begin:
+  \spath_reallength:Nn \l_@@_tmpa_int {#2}
+      
+  \tl_set:Nx \l_@@_tmpb_tl
+  {\fp_to_decimal:n {(#1) * (\l_@@_tmpa_int)}}
+  \spath_transformation_at:NnV \l_@@_tmpc_tl {#2} \l_@@_tmpb_tl
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \@@_transform_to:nn #1#2
+{
+  \@@_transform_to_aux:nn {#1}{#2}
+  \exp_last_unbraced:NV \pgfsettransformentries \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_transform_to:nn {nv}
+\cs_new_protected_nopar:Npn \@@_transform_upright_to:nn #1#2
+{
+  \@@_transform_to_aux:nn {#1}{#2}
+  \fp_compare:nT { \tl_item:Nn \g_@@_output_tl {4} < 0}
+  {
+    \tl_gset:Nx \g_@@_output_tl
+    {
+      { \fp_eval:n { - (\tl_item:Nn \g_@@_output_tl {1})} }
+      { \fp_eval:n { - (\tl_item:Nn \g_@@_output_tl {2})} }
+      { \fp_eval:n { - (\tl_item:Nn \g_@@_output_tl {3})} }
+      { \fp_eval:n { - (\tl_item:Nn \g_@@_output_tl {4})} }
+      { \tl_item:Nn \g_@@_output_tl {5} }
+      { \tl_item:Nn \g_@@_output_tl {6} }
+    }
+  }
+  \exp_last_unbraced:NV \pgfsettransformentries \g_@@_output_tl
+  \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \@@_transform_upright_to:nn {nv}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Keys}
 % Now we define all of our keys.
 %
 %    \begin{macrocode}
@@ -5224,6 +7940,14 @@
   },
 %    \end{macrocode}
 %
+% Hook in to the end of the path construction
+%
+%    \begin{macrocode}
+  at~ end~ path~ construction/.code={
+    \tl_put_right:Nn \l_@@_tikzpath_finish_tl {#1}
+  },
+%    \end{macrocode}
+%
 % Keys for saving and cloning a soft path.
 %
 %    \begin{macrocode}
@@ -5231,8 +7955,8 @@
     \tikz at addmode{
       \spath_get_current_path:N \l_@@_tmpa_tl
       \spath_bake_round:NV \l_@@_tmpa_tl \l_@@_tmpa_tl
-      \spath_save_path:cV
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \spath_bake_shorten:NV \l_@@_tmpa_tl \l_@@_tmpa_tl
+      \spath_save_path:cV {\@@_path_name:n {#1}}
       \l_@@_tmpa_tl
     }
   },
@@ -5240,38 +7964,30 @@
     \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}
+      \spath_bake_shorten:NV \l_@@_tmpa_tl \l_@@_tmpa_tl
+      \spath_gsave_path:cV {\@@_path_name:n {#1}}
       \l_@@_tmpa_tl
     }
   },
   clone/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \tl_clear_new:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \tl_set_eq:cc
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_path:nnn {
+        \tl_clear_new:c {\@@_path_name:n {#1}}
+        \tl_set_eq:cc {\@@_path_name:n {#1}}
+      }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #2 }
-    }
+    {#2}{}
   },
   clone~ global/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \tl_gclear_new:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \tl_gset_eq:cc
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_path:nnn {
+        \tl_gclear_new:c {\@@_path_name:n {#1}}
+        \tl_gset_eq:cc {\@@_path_name:n {#1}}
+      }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #2 }
-    }
+    {#2}{}
   },
 %    \end{macrocode}
 %
@@ -5279,15 +7995,14 @@
 %
 %    \begin{macrocode}
   save~ to~ aux/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \spath_save_to_aux:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_path:nnn {
+        \spath_save_to_aux:c
+      }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
 %    \end{macrocode}
 %
@@ -5295,15 +8010,14 @@
 %
 %    \begin{macrocode}
   export~ to~ svg/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \spath_export_to_svg:nv {#1}
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_path:nnn {
+        \spath_export_to_svg:nv {#1}
+      }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
 %    \end{macrocode}
 %
@@ -5317,6 +8031,8 @@
     \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_@@_current_transformation_bool
+    \bool_set_true:N \l_spath_movetorelevant_bool
     \tl_clear:N \l_@@_joinpath_tl
     \tl_clear:N \l_@@_transformation_tl
     \tikzset{
@@ -5324,103 +8040,11 @@
       #1
     }
 
-    \tl_if_exist:cTF
+    \@@_check_path:nVn
     {
-      \tl_use:N \l_@@_prefix_tl
-      \tl_use:N \l_@@_joinpath_tl
-      \tl_use:N \l_@@_suffix_tl
-    }
-    {
-      \tl_if_empty:cT
-      {
-        \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
-      {
-        \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
-      }
+      \@@_use_path:v
+    } \l_@@_joinpath_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
-    }
-    {
-      \msg_warning:nnx
-      { spath3 }
-      { missing soft path }
-      {\tl_use:N \l_@@_joinpath_tl }
-    }
   },
 %    \end{macrocode}
 %
@@ -5453,23 +8077,10 @@
 %
 %    \begin{macrocode}
   show/.code={
-    \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}
-      {
-        \msg_warning:nnn { spath3 } { empty soft path } { #1 }
-      }
-      {
-        \iow_term:n {---~ soft~ path~ #1~ ---}
-        \spath_show:v
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    \@@_check_path:nnn {
+      \iow_term:n {---~ soft~ path~ #1~ ---}
+      \spath_show:v
+    } {#1} {}
   },
 %    \end{macrocode}
 %
@@ -5479,98 +8090,25 @@
 %
 %    \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
+    \bool_set_false:N \l_@@_current_transformation_bool
+    \tl_clear:N \l_@@_joinpath_tl
+    \tl_clear:N \l_@@_transformation_tl
+    \tikzset{
+      spath/join/.cd,
+      #2
+    }
+
+    \@@_maybe_current_path_reuse:nnn
     {
-      \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
+      \@@_check_two_paths:nnVn
       {
-        \tl_use:N \l_@@_prefix_tl
-        \tl_use:N \l_@@_joinpath_tl
-        \tl_use:N \l_@@_suffix_tl
+        \@@_join_with:cv
       }
-      {
-        \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}
-        \l_@@_joinpath_tl
-      }
-      {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        {\tl_use:N \l_@@_joinpath_tl }
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { \l_@@_joinpath_tl {} }
   },
 %    \end{macrocode}
 %
@@ -5578,26 +8116,22 @@
 %
 %    \begin{macrocode}
   spot~ weld/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_spot_weld_components:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_spot_weld_components:c
+      }
+    } {#1} { {} }
   },
   spot~ weld~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_spot_gweld_components:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_spot_gweld_components:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
@@ -5605,26 +8139,22 @@
 %
 %    \begin{macrocode}
   reverse/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_reverse:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_reverse:c
+      }
+    } {#1} { {} }
   },
   reverse~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_reverse:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_greverse:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
@@ -5632,32 +8162,26 @@
 %  
 %    \begin{macrocode}
   span/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \@@_process_tikz_point:Nn \l_@@_tmpa_tl {#2}
-      \@@_process_tikz_point:Nn \l_@@_tmpb_tl {#3}
-      \spath_span:cVV
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \l_@@_tmpa_tl \l_@@_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \@@_process_tikz_point:Nn \l_@@_tmpa_tl {#2}
+        \@@_process_tikz_point:Nn \l_@@_tmpb_tl {#3}
+        \spath_span:cVV
+      }
+    } {#1} { {} \l_@@_tmpa_tl \l_@@_tmpb_tl }
   },
   span~ global/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \@@_process_tikz_point:Nn \l_@@_tmpa_tl {#2}
-      \@@_process_tikz_point:Nn \l_@@_tmpb_tl {#3}
-      \spath_gspan:cVV
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \l_@@_tmpa_tl \l_@@_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \@@_process_tikz_point:Nn \l_@@_tmpa_tl {#2}
+        \@@_process_tikz_point:Nn \l_@@_tmpb_tl {#3}
+        \spath_span:cVV
+      }
+    } {#1} { {} \l_@@_tmpa_tl \l_@@_tmpb_tl }
   },
 %    \end{macrocode}
 % 
@@ -5668,7 +8192,7 @@
     to~path={
       [
         spath/span={#1}{(\tikztostart)}{(\tikztotarget)},
-        spath/append~no~move={#1},
+        spath/use={#1,weld},
       ]
       \tikztonodes
     }
@@ -5675,62 +8199,27 @@
   },
 %    \end{macrocode}  
 %
+%
 % Splice three paths together, transforming the middle one so that it exactly fits between the first and third.
 %  
 %    \begin{macrocode}
   splice/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_three_paths:nnnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #3 \tl_use:N \l_@@_suffix_tl}
-        {
-          \spath_splice_between:cvv
-          {\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}
-          {\tl_use:N \l_@@_prefix_tl #3 \tl_use:N \l_@@_suffix_tl}
-        }
-        {
-          \msg_warning:nnn { spath3 } { missing soft path } { #3 }
-        }
+        \spath_splice_between:cvv
       }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {#2} {#3} {} }
   },
   splice~ global/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_three_paths:nnnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #3 \tl_use:N \l_@@_suffix_tl}
-        {
-          \spath_gsplice_between:cvv
-          {\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}
-          {\tl_use:N \l_@@_prefix_tl #3 \tl_use:N \l_@@_suffix_tl}
-        }
-        {
-          \msg_warning:nnn { spath3 } { missing soft path } { #3 }
-        }
+        \spath_gsplice_between:cvv
       }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {#2} {#3} {} }
   },
 %    \end{macrocode}
 %
@@ -5742,447 +8231,177 @@
 %
 %    \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_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}
-        }
+      \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
+    }
 
-        \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_set_eq:cN
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-        \l_@@_tmpa_tl
-      }
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_two_paths:nnVn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l_@@_tmpc_tl }
+        \@@_join_components_with:cvV
       }
+    } {#1} { \l_@@_tmpc_tl {} \l_@@_tmpd_tl  } 
+  },
+  join~ components~ globally~ with/.code~2~args={
+    \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} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l_@@_tmpc_tl {#2}
+      \tl_clear:N \l_@@_tmpd_tl
     }
-  },
-  join~ components~ globally~ with/.code~2~args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \@@_check_two_paths:nnVn
       {
-        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+        \@@_gjoin_components_with:cvV
       }
-      {
-        \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}
-        }
+    } {#1} { \l_@@_tmpc_tl {} \l_@@_tmpd_tl  } 
+  },
+  join~ components~ upright~ with/.code~2~args={
+    \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
+    }
 
-        \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
-      }
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_two_paths:nnVn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l_@@_tmpc_tl }
+        \@@_join_components_upright_with:cvV
       }
+    } {#1} { \l_@@_tmpc_tl {} \l_@@_tmpd_tl  } 
+  },
+  join~ components~ globally~ upright~ with/.code~2~args={
+    \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} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l_@@_tmpc_tl {#2}
+      \tl_clear:N \l_@@_tmpd_tl
     }
-  },
-  join~ components~ upright~ with/.code~2~args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \@@_check_two_paths:nnVn
       {
-        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+        \@@_gjoin_components_upright_with:cvV
       }
-      {
-        \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_set_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 }
-      }
+    } {#1} { \l_@@_tmpc_tl {} \l_@@_tmpd_tl  } 
+  },
+  join~ components~ with~ bezier/.code={
+    \tl_if_head_is_group:nTF {#1}
+    {
+      \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#1} {1} }
+      \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#1} {2} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l_@@_tmpc_tl {#1}
+      \tl_clear:N \l_@@_tmpd_tl
     }
+    
+    \@@_maybe_current_path_reuse:nVn
+    {
+      \@@_check_path:nnn
+      {
+        \@@_join_components_with_bezier:cV
+      }
+    } \l_@@_tmpc_tl { {} \l_@@_tmpd_tl }
   },
-  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}
+  join~ components~ globally~ with~ bezier/.code~2~args={
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \@@_check_path:nnn
       {
-        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+        \@@_gjoin_components_with_bezier:cn
       }
+    } {#1} { {} {#2} }
+  },
+%    \end{macrocode}
+%
+% Close a path.
+%
+%    \begin{macrocode}
+  close/.code={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \tl_set:Nn \l_@@_tmpc_tl {#2}
-        \tl_clear:N \l_@@_tmpd_tl
+        \spath_close:c
       }
-      \tl_if_exist:cTF
+    } {#1} { {} }
+  },
+  close~ globally/.code={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \tl_use:N \l_@@_prefix_tl
-        \tl_use:N \l_@@_tmpc_tl
-        \tl_use:N \l_@@_suffix_tl
+        \spath_gclose:c
       }
+    } {#1} { {} }
+  },
+%    \end{macrocode}
+%
+% Open a path.
+%
+%    \begin{macrocode}
+  open/.code={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \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
+        \spath_open:c
       }
+    } {#1} { {} }
+  },
+  open~ globally/.code={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l_@@_tmpc_tl }
+        \spath_gopen:c
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
-% Close a path.
+% Close a path, ensuring that the end point is exactly where it will close up to.
 %
 %    \begin{macrocode}
-  close/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+  adjust~ and~ close/.code={
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_close:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_adjust_close:c
+      }
+    } {#1} { {} }
   },
-  close~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+  adjust~ and~ close~ globally/.code={
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gclose:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_adjust_gclose:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
@@ -6190,118 +8409,192 @@
 %
 %    \begin{macrocode}
   close~ with/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_two_paths:nnnn
       {
         \spath_close_with: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 } { #1 }
-    }
+    } {#1} { {#2} {} } 
   },
   close~ globally~ with/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+      \@@_check_two_paths:nnnn
       {
         \spath_gclose_with: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}
       }
+    } {#1} { {#2} {} } 
+  },
+%    \end{macrocode}
+%
+% Close a path with a curve.
+%
+%    \begin{macrocode}
+  close~ with~ curve/.code={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \spath_close_with_curve:c
       }
-    }
+    } {#1} { {} }
+  },
+  close~ globally~ with~ curve/.code={
+    \@@_maybe_current_path_reuse:nnn
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gclose_with_curve:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
-% These keys shorten the path.
+% These keys shorten the path by a dimension.
 %
 %    \begin{macrocode}
   shorten~ at~ end/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_shorten_at_end:cn
+      }
+    } {#1} { {} {#2} }
   },
   shorten~ at~ start/.code~ 2~ args ={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_shorten_at_start:cn
+      }
+    } {#1} { {} {#2} }
   },
   shorten~ at~ both~ ends/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_shorten_at_both_ends:cn
+      }
+    } {#1} { {} {#2} }
   },
   shorten~ globally~ at~ end/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gshorten_at_end:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gshorten_at_end:cn
+      }
+    } {#1} { {} {#2} }
   },
   shorten~ globally~ at~ start/.code~ 2~ args ={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gshorten_at_start:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gshorten_at_start:cn
+      }
+    } {#1} { {} {#2} }
   },
   shorten~ globally~ at~ both~ ends/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl} {#2}
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gshorten_at_both_ends:cn
+      }
+    } {#1} { {} {#2} }
+  },
+%    \end{macrocode}
+%
+% These keys split a path at a parameter, the \texttt{keep} versions only keep one part of the resultant path.
+%
+%    \begin{macrocode}
+  split~ at/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_split_at_normalised:cn
+      }
+    } {#1} { {} {#2} }
   },
+  split~ globally~ at/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_gsplit_at_normalised:cn
+      }
+    } {#1} { {} {#2} }
+  },
+  split~ at~ into/.code~ n~ args={4}{
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_split_at_normalised:ccvn {\@@_path_name:n {#1}}
+        {\@@_path_name:n {#2}}
+      }
+    } {#3} { {} {#4} }
+  },
+  split~ globally~ at~ into/.code~ n~ args={4}{
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_gsplit_at_normalised:ccvn {\@@_path_name:n {#1}}
+        {\@@_path_name:n {#2}}
+      }
+    } {#3} { {} {#4} }
+  },
+  split~ at~ keep~ start/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_split_at_normalised_keep_start:cn
+      }
+    } {#1} { {} {#2} }
+  },
+  split~ globally~ at~ keep~ start/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_gsplit_at_normalised_keep_start:cn
+      }
+    } {#1} { {} {#2} }
+  },
+  split~ at~ keep~ end/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_split_at_normalised_keep_end:cn
+      }
+    } {#1} { {} {#2} }
+  },
+  split~ globally~ at~ keep~ end/.code~ 2~ args={
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
+      {
+        \spath_gsplit_at_normalised_keep_end:cn
+      }
+    } {#1} { {} {#2} }
+  },
+  split~ at~ keep~ middle/.style~ n~ args={3}{
+    /tikz/spath/split~ at~ keep~ start={#1}{#3},
+    /tikz/spath/split~ at~ keep~ end={#1}{(#2)/(#3)},
+  },
+  split~ globally~ at~ keep~ middle/.style~ n~ args={3}{
+    /tikz/spath/split~ globally~ at~ keep~ start={#1}{#3},
+    /tikz/spath/split~ globally~ at~ keep~ end={#1}{(#2)/(#3)},
+  },
 %    \end{macrocode}
 %
 % This translates the named path.
@@ -6308,26 +8601,22 @@
 %
 %    \begin{macrocode}
   translate/.code~ n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_translate:cnn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{#2}{#3}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_translate:cnn
+      }
+    } {#1} { {} {#2}{#3} }
   },
   translate~ globally/.code~ n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gtranslate:cnn
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{#2}{#3}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gtranslate:cnn
+      }
+    } {#1} { {} {#2}{#3} }
   },
 %    \end{macrocode}
 %
@@ -6335,26 +8624,22 @@
 %
 %    \begin{macrocode}
   normalise/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_normalise:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_normalise:c
+      }
+    } {#1} { {} }
   },
   normalise~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gnormalise:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gnormalise:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
@@ -6362,46 +8647,36 @@
 %
 %    \begin{macrocode}
   transform/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \group_begin:
+    \pgftransformreset
+    \tikzset{#2}
+    \pgfgettransform \l_@@_tmpa_tl
+    \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpa_tl
+    \group_end:
+    
+    \@@_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \pgftransformreset
-      \tikzset{#2}
-      \pgfgettransform \l_@@_tmpa_tl
-      \tl_gset:Nn \g_@@_smuggle_tl
+      \@@_check_path:nnn
       {
-        \spath_transform:cnnnnnn
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \spath_transform:cV
       }
-      \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
-      \group_end:
-      \tl_use:N \g_@@_smuggle_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \g_@@_smuggle_tl }
   },
   transform~globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \group_begin:
+    \pgftransformreset
+    \tikzset{#2}
+    \pgfgettransform \l_@@_tmpa_tl
+    \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpa_tl
+    \group_end:
+    
+    \@@_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \pgftransformreset
-      \tikzset{#2}
-      \pgfgettransform \l_@@_tmpa_tl
-      \tl_gset:Nn \g_@@_smuggle_tl
+      \@@_check_path:nnn
       {
-        \spath_gtransform:cnnnnnn
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+        \spath_gtransform:cV
       }
-      \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
-      \group_end:
-      \tl_use:N \g_@@_smuggle_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \g_@@_smuggle_tl }
   },
 %    \end{macrocode}
 %
@@ -6408,29 +8683,19 @@
 % Splits first path where it intersects with the second.
 %
 %    \begin{macrocode}
-  split~ at~ intersections~ with/.code~ n~ args={2}{
+  split~ at~ intersections~ with/.code~ 2~ args={
     \tl_if_exist:cTF
     {
       tikz at library@intersections at loaded
     }
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_two_paths_reuse_first:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        \@@_check_two_paths:nnnn
         {
-          \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}
+          \spath_split_path_at_intersections:cv            
         }
-        {
-          \msg_warning:nnn { spath3 } { missing soft path } { #2 }
-        }
-      }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6442,23 +8707,13 @@
       tikz at library@intersections at loaded
     }
     {
-    \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_two_paths_reuse_first:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        \@@_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6475,23 +8730,13 @@
       tikz at library@intersections at loaded
     }
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_two_paths_reuse_both:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        \@@_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6503,23 +8748,13 @@
       tikz at library@intersections at loaded
     }
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_two_paths_reuse_both:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+        \@@_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6536,15 +8771,13 @@
       tikz at library@intersections at loaded
     }
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_path_reuse:nnn
       {
-        \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 }
-      }
+        \@@_check_path:nnn
+        {
+          \spath_split_at_self_intersections:c
+        }
+      } {#1} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6556,15 +8789,13 @@
       tikz at library@intersections at loaded
     }
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_path_reuse:nnn
       {
-        \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 }
-      }
+        \@@_check_path:nnn
+        {
+          \spath_gsplit_at_self_intersections:c
+        }
+      } {#1} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -6576,64 +8807,24 @@
 %
 %    \begin{macrocode}
   get~ components~ of/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \clist_clear_new:N #2
-      \spath_components_to_seq:Nv
-      \l_@@_tmpa_seq
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \seq_map_inline:Nn \l_@@_tmpa_seq
-      {
-        \tl_new:c
-        {
-          \tl_use:N \l_@@_prefix_tl
-          anonymous_\int_use:N \g_@@_anon_int
-          \tl_use:N \l_@@_suffix_tl
-        }
-        \tl_set:cn
-        {
-          \tl_use:N \l_@@_prefix_tl
-          anonymous_\int_use:N \g_@@_anon_int
-          \tl_use:N \l_@@_suffix_tl
-        } {##1}
-        \clist_put_right:Nx #2 {anonymous_\int_use:N \g_@@_anon_int}
-        \int_gincr:N \g_@@_anon_int
+      \@@_check_path:nnn {
+        \@@_get_components:Nv #2
       }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
   get~ components~ of~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \clist_gclear_new:N #2
-      \spath_components_to_seq:Nv
-      \l_@@_tmpa_seq
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \seq_map_inline:Nn \l_@@_tmpa_seq
-      {
-        \tl_new:c
-        {
-          \tl_use:N \l_@@_prefix_tl
-          anonymous_\int_use:N \g_@@_anon_int
-          \tl_use:N \l_@@_suffix_tl
-        }
-        \tl_gset:cn
-        {
-          \tl_use:N \l_@@_prefix_tl
-          anonymous_\int_use:N \g_@@_anon_int
-          \tl_use:N \l_@@_suffix_tl
-        } {##1}
-        \clist_gput_right:Nx #2 {anonymous_\int_use:N \g_@@_anon_int}
-        \int_gincr:N \g_@@_anon_int
+      \@@_check_path:nnn {
+        \@@_gget_components:Nv #2
       }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
 %    \end{macrocode}
 %
@@ -6641,33 +8832,14 @@
 %
 %    \begin{macrocode}
   render~ components/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path:nn
     {
-      \group_begin:
-      \spath_components_to_seq:Nv
-      \l_@@_tmpa_seq
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
-      {
-        \spath_tikz_path:nn
-        {
-          every~ spath~ component/.try,
-          spath ~component~ ##1/.try,
-          spath ~component/.try={##1},
-          every~ #1~ component/.try,
-          #1 ~component~ ##1/.try,
-          #1 ~component/.try={##1},
-        }
-        {
-          ##2
-        }
+      \@@_check_path:nnn {
+        \@@_render_components:nv {#1}
       }
-      \group_end:
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
 %    \end{macrocode}
 %
@@ -6676,148 +8848,86 @@
 %
 %    \begin{macrocode}
   insert~ gaps~ after~ components/.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}
     {
-      \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}
+      \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
+    }
 
-      \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
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \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}}
-        }
+        \@@_insert_gaps_after_components:cVV
       }
-      {
-        \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
-            }
-          }
-        }
-      }
+    } {#1} { {} \l_@@_tmpc_tl \l_@@_tmpd_tl  } 
+  },
+  insert~ gaps~ globally~ after~ components/.code~ 2~ args={
+    \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_clear:N \l_@@_tmpb_seq
-      \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \tl_set:Nn \l_@@_tmpa_tl {##2}
-        \seq_if_in:NnT \g_@@_tmpa_seq {##1}
-        {
-          \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 {\l_@@_tmpc_tl/2}
-        }
-        \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
+        \@@_ginsert_gaps_after_components:cVV
       }
-      \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpb_seq {} }
-      \group_end:
-      \tl_set_eq:cN
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \g_@@_output_tl
-      \tl_gclear:N \g_@@_output_tl
+    } {#1} { {} \l_@@_tmpc_tl \l_@@_tmpd_tl  } 
+  },
+%    \end{macrocode}
+%
+% This puts gaps between segments of a soft path.
+% The list of segments is passed through a \Verb+\foreach+ loop so can use the shortcut syntax from those loops.
+%
+%    \begin{macrocode}
+  insert~ gaps~ after~ segments/.code~ 2~ args={
+    \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} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l_@@_tmpc_tl {#2}
+      \tl_clear:N \l_@@_tmpd_tl
     }
-  },
-  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}
+
+    \@@_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \tl_if_head_is_group:nTF {#2}
+      \@@_check_path:nnn
       {
-        \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+        \@@_insert_gaps_after_segments:cVV
       }
-      {
-        \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}
+    } {#1} { {} \l_@@_tmpc_tl \l_@@_tmpd_tl  } 
+  },
+  insert~ gaps~ globally~ after~ segments/.code~ 2~ args={
+    \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
+    }
 
-      \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
+    \@@_maybe_current_path_reuse:nnn
+    {
+      \@@_check_path:nnn
       {
-        \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}}
-        }
+        \@@_ginsert_gaps_after_segments:cVV
       }
-      {
-        \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
-            }
-          }
-        }
-      }
-
-      \seq_clear:N \l_@@_tmpb_seq
-      \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
-      {
-        \tl_set:Nn \l_@@_tmpa_tl {##2}
-        \seq_if_in:NnT \g_@@_tmpa_seq {##1}
-        {
-          \spath_shorten_at_end:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
-        }
-        \seq_if_in:NnT \g_@@_tmpb_seq {##1}
-        {
-          \spath_shorten_at_start:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
-        }
-        \seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
-      }
-      \tl_gset:Nx \g_@@_output_tl {\seq_use:Nn \l_@@_tmpb_seq {} }
-      \group_end:
-      \tl_gset_eq:cN
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \g_@@_output_tl
-      \tl_gclear:N \g_@@_output_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \l_@@_tmpc_tl \l_@@_tmpd_tl  } 
   },
 %    \end{macrocode}
 %
@@ -6825,54 +8935,22 @@
 %
 %    \begin{macrocode}
   join~ components/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g_@@_tmpa_seq
-      \foreach \l_@@_tmpa_tl in {#2}
+      \@@_check_path:nnn
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+        \@@_join_components:cn
       }
-      \seq_gsort:Nn \g_@@_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} > {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \seq_map_inline:Nn \g_@@_tmpa_seq
-      {
-        \spath_join_component:cn
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{##1}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} } 
   },
   join~ components~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g_@@_tmpa_seq
-      \foreach \l_@@_tmpa_tl in {#2}
+      \@@_check_path:nnn
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+        \@@_gjoin_components:cn
       }
-      \seq_gsort:Nn \g_@@_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} > {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \seq_map_inline:Nn \g_@@_tmpa_seq
-      {
-        \spath_gjoin_component:cn
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}{##1}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} } 
   },
 %    \end{macrocode}
 %
@@ -6880,26 +8958,22 @@
 %
 %    \begin{macrocode}
   remove~ empty~ components/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_remove_empty_components:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_remove_empty_components:c
+      }
+    } {#1} { {} }
   },
   remove~ empty~ components~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \spath_gremove_empty_components:c
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_gremove_empty_components:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
@@ -6907,120 +8981,46 @@
 %
 %    \begin{macrocode}
   replace~ lines/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \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 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_replace_lines:c
+      }
+    } {#1} { {} }
   },
   replace~ lines~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \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 }
-    }
+      \@@_check_path:nnn
+      {
+        \spath_greplace_lines:c
+      }
+    } {#1} { {} }
   },
 %    \end{macrocode}
 %
 %
-% Join the specified components together, joining each to its previous one.
+% Remove the specified components.
 %
 %    \begin{macrocode}
   remove~ components/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g_@@_tmpa_seq
-      \foreach \l_@@_tmpa_tl in {#2}
+      \@@_check_path:nnn
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+        \@@_remove_components:cn
       }
-      \seq_gsort:Nn \g_@@_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} < {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \spath_components_to_seq:Nv
-      \l_@@_tmpa_seq
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpa_tl
-      {
-        \tl_clear:N \l_@@_tmpa_tl
-      }
-      \seq_clear:N \l_@@_tmpb_seq
-      \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
-      {
-        \tl_set:Nn \l_@@_tmpb_tl {##1}
-        \tl_if_eq:NNTF \l_@@_tmpb_tl \l_@@_tmpa_tl
-        {
-          \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpa_tl
-          {
-            \tl_clear:N \l_@@_tmpa_tl
-          }
-        }
-        {
-          \seq_put_right:Nn \l_@@_tmpb_seq {##2}
-        }
-      }
-      \tl_set:cx {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      {\seq_use:Nn \l_@@_tmpb_seq {} }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
   remove~ components~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+    \@@_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g_@@_tmpa_seq
-      \foreach \l_@@_tmpa_tl in {#2}
+      \@@_check_path:nnn
       {
-        \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+        \@@_gremove_components:cn
       }
-      \seq_gsort:Nn \g_@@_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} < {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \spath_components_to_seq:Nv
-      \l_@@_tmpa_seq
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpa_tl
-      {
-        \tl_clear:N \l_@@_tmpa_tl
-      }
-      \seq_clear:N \l_@@_tmpb_seq
-      \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
-      {
-        \tl_set:Nn \l_@@_tmpb_tl {##1}
-        \tl_if_eq:NNTF \l_@@_tmpb_tl \l_@@_tmpa_tl
-        {
-          \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpa_tl
-          {
-            \tl_clear:N \l_@@_tmpa_tl
-          }
-        }
-        {
-          \seq_put_right:Nn \l_@@_tmpb_seq {##2}
-        }
-      }
-      \tl_gset:cx {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      {\seq_use:Nn \l_@@_tmpb_seq {} }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
 %    \end{macrocode}
 %   
@@ -7037,29 +9037,25 @@
   maybe~ spot~ weld/.code={
     \bool_if:NF \l_@@_draft_bool
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_path_reuse:nnn
       {
-        \spath_spot_weld_components:c
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      }
+        \@@_check_path:nnn
+        {
+          \spath_spot_weld_components:c
+        }
+      } {#1} { {} }
     }
   },
   maybe~ spot~ weld~ globally/.code={
     \bool_if:NF \l_@@_draft_bool
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+      \@@_maybe_current_path_reuse:nnn
       {
-        \spath_spot_gweld_components:c
-        {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
-      }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      }
+        \@@_check_path:nnn
+        {
+          \spath_spot_gweld_components:c
+        }
+      } {#1} { {} }
     }
   },
 %    \end{macrocode}
@@ -7068,40 +9064,16 @@
 %
 %    \begin{macrocode}
   transform~ to/.code~ 2~ args={
-    \group_begin:
-    \tl_if_exist:cTF
+    \@@_maybe_current_path:nn
     {
-      \tl_use:N \l_@@_prefix_tl
-      #1
-      \tl_use:N \l_@@_suffix_tl
-    }
-    {
-      \spath_reallength:Nv
-      \l_@@_tmpa_int
-      {
-        \tl_use:N \l_@@_prefix_tl
-        #1
-        \tl_use:N \l_@@_suffix_tl
+      \@@_check_path:nnn {
+        \@@_transform_to:nv {#2}
       }
-      
-      \tl_set:Nx \l_@@_tmpb_tl
-      {\fp_to_decimal:n {(#2) * (\l_@@_tmpa_int)}}
-      \spath_transformation_at:NvV \l_@@_tmpc_tl
-      {
-        \tl_use:N \l_@@_prefix_tl
-        #1
-        \tl_use:N \l_@@_suffix_tl
-      }
-      \l_@@_tmpb_tl
-      \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpc_tl
     }
+    {#1}
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      \tl_gset_eq:NN \g_@@_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} }
+      \pgfsettransformentries {1}{0}{0}{1}{0pt}{0pt}
     }
-    \group_end:
-    \exp_last_unbraced:NV \pgfsettransformentries \g_@@_smuggle_tl
-    \tl_gclear:N \g_@@_smuggle_tl
   },
 %    \end{macrocode}
 %
@@ -7109,52 +9081,16 @@
 %
 %    \begin{macrocode}
   upright~ transform~ to/.code~ 2~ args={
-    \group_begin:
-    \tl_if_exist:cTF
+    \@@_maybe_current_path:nn
     {
-      \tl_use:N \l_@@_prefix_tl
-      #1
-      \tl_use:N \l_@@_suffix_tl
-    }
-    {
-      \spath_reallength:Nv
-      \l_@@_tmpa_int
-      {
-        \tl_use:N \l_@@_prefix_tl
-        #1
-        \tl_use:N \l_@@_suffix_tl
+      \@@_check_path:nnn {
+        \@@_transform_upright_to:nv {#2}
       }
-      
-      \tl_set:Nx \l_@@_tmpb_tl
-      {\fp_to_decimal:n {(#2) * (\l_@@_tmpa_int)}}
-      \spath_transformation_at:NvV \l_@@_tmpc_tl
-      {
-        \tl_use:N \l_@@_prefix_tl
-        #1
-        \tl_use:N \l_@@_suffix_tl
-      }
-      \l_@@_tmpb_tl
-      \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpc_tl
     }
+    {#1}
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      \tl_gset_eq:NN \g_@@_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} }
+      \pgfsettransformentries {1}{0}{0}{1}{0pt}{0pt}
     }
-    \fp_compare:nT { \tl_item:Nn \g_@@_smuggle_tl {4} < 0}
-    {
-      \tl_gset:Nx \g_@@_smuggle_tl
-      {
-        { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {1})} }
-        { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {2})} }
-        { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {3})} }
-        { \fp_eval:n { - (\tl_item:Nn \g_@@_smuggle_tl {4})} }
-        { \tl_item:Nn \g_@@_smuggle_tl {5} }
-        { \tl_item:Nn \g_@@_smuggle_tl {6} }
-      }
-    }
-    \group_end:
-    \exp_last_unbraced:NV \pgfsettransformentries \g_@@_smuggle_tl
-    \tl_gclear:N \g_@@_smuggle_tl
   },
 %    \end{macrocode}
 %
@@ -7162,19 +9098,43 @@
 %
 %    \begin{macrocode}
   knot/.style~ n~ args={3}{
-    spath/split~ at~ self~ intersections=#1,
-    spath/remove~ empty~ components=#1,
-    spath/insert~ gaps~ after~ components={#1}{#2}{#3},
-    spath/maybe~ spot~ weld=#1,
-    spath/render~ components=#1
+    /tikz/spath/split~ at~ self~ intersections=#1,
+    /tikz/spath/remove~ empty~ components=#1,
+    /tikz/spath/insert~ gaps~ after~ components={#1}{#2}{#3},
+    /tikz/spath/maybe~ spot~ weld=#1,
+    /tikz/spath/render~ components=#1
   },
   global~ knot/.style~ n~ args={3}{
-    spath/split~ globally~ at~ self~ intersections=#1,
-    spath/remove~ empty~ components~ globally=#1,
-    spath/insert~ gaps~ globally ~after~ components={#1}{#2}{#3},
-    spath/maybe~ spot~ weld~ globally=#1,
-    spath/render~ components=#1
+    /tikz/spath/split~ globally~ at~ self~ intersections=#1,
+    /tikz/spath/remove~ empty~ components~ globally=#1,
+    /tikz/spath/insert~ gaps~ globally ~after~ components={#1}{#2}{#3},
+    /tikz/spath/maybe~ spot~ weld~ globally=#1,
+    /tikz/spath/render~ components=#1
   },
+%    \end{macrocode}
+%
+% For single argument commands which take a path as their argument, set the default to be \Verb+current+ so that they use the current path.
+%
+%    \begin{macrocode}
+  show/.default=current,
+  spot~ weld/.default=current,
+  spot~ weld~ globally/.default=current,
+  reverse/.default=current,
+  reverse~ globally/.default=current,
+  close/.default=current,
+  close~ globally/.default=current,
+  open/.default=current,
+  open~ globally/.default=current,
+  adjust~ and~ close/.default=current,
+  adjust~ and~ close~ globally/.default=current,
+  close~ with~ curve/.default=current,
+  close~ globally~ with~ curve/.default=current,
+  remove~ empty~ components/.default=current,
+  remove~ empty~ components~ globally/.default=current,
+  replace~ lines/.default=current,
+  replace~ lines~ globally/.default=current,
+  maybe~ spot~ weld/.default=current,
+  maybe~ spot~ weld~ globally/.default=current,
 }
 %    \end{macrocode}
 %
@@ -7181,6 +9141,27 @@
 % This defines a coordinate system that finds a position on a soft path.
 %
 %    \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_get_point_at:nn #1#2
+{
+  \group_begin:
+  \spath_reallength:Nn \l_@@_tmpa_int {#2}
+  \tl_set:Nx \l_@@_tmpb_tl
+  {\fp_to_decimal:n {(#1) * (\l_@@_tmpa_int)}}
+  \spath_point_at:NnV \l_@@_tmpc_tl {#2} \l_@@_tmpb_tl
+
+  \tl_clear:N \l_@@_tmpd_tl
+  \tl_put_right:Nn \l_@@_tmpd_tl {\pgf at x=}
+  \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {1}}
+  \tl_put_right:Nn \l_@@_tmpd_tl {\relax}
+  \tl_put_right:Nn \l_@@_tmpd_tl {\pgf at y=}
+  \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {2}}
+  \tl_put_right:Nn \l_@@_tmpd_tl {\relax}
+  
+  \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpd_tl
+  \group_end:
+ }
+\cs_generate_variant:Nn \@@_get_point_at:nn {VV, Vn, Vv}
+
 \tikzdeclarecoordinatesystem{spath}{%
   \group_begin:
   \tl_set:Nn \l_@@_tmpa_tl {#1}
@@ -7190,55 +9171,25 @@
   \seq_pop_right:NN \l_@@_tmpa_seq \l_@@_tmpb_tl
 
   \tl_set:Nx \l_@@_tmpa_tl { \seq_use:Nn \l_@@_tmpa_seq {~} }
-  \tl_if_exist:cTF
+
+  \@@_maybe_current_path:nV
   {
-    \tl_use:N \l_@@_prefix_tl
-    \tl_use:N \l_@@_tmpa_tl
-    \tl_use:N \l_@@_suffix_tl
-  }
-  {
-
-    \tl_set_eq:Nc
-    \l_@@_tmpa_tl
-    {
-      \tl_use:N \l_@@_prefix_tl
-      \tl_use:N \l_@@_tmpa_tl
-      \tl_use:N \l_@@_suffix_tl
+    \@@_check_path:nnn {
+      \@@_get_point_at:Vv \l_@@_tmpb_tl
     }
-
-    \tl_if_empty:NTF \l_@@_tmpa_tl
-    {
-      \tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin
-    }
-    {
-      \spath_reallength:NV \l_@@_tmpa_int \l_@@_tmpa_tl
-      \tl_set:Nx \l_@@_tmpb_tl
-      {\fp_to_decimal:n {(\l_@@_tmpb_tl) * (\l_@@_tmpa_int)}}
-      \spath_point_at:NVV \l_@@_tmpc_tl \l_@@_tmpa_tl \l_@@_tmpb_tl
-
-      \tl_clear:N \l_@@_tmpd_tl
-      \tl_put_right:Nn \l_@@_tmpd_tl {\pgf at x=}
-      \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {1}}
-      \tl_put_right:Nn \l_@@_tmpd_tl {\relax}
-      \tl_put_right:Nn \l_@@_tmpd_tl {\pgf at y=}
-      \tl_put_right:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpc_tl {2}}
-      \tl_put_right:Nn \l_@@_tmpd_tl {\relax}
-      \tl_gset_eq:NN \g_@@_smuggle_tl \l_@@_tmpd_tl
-    }
   }
+  \l_@@_tmpa_tl
   {
-    \msg_warning:nnx
-    { spath3 }
-    { missing soft path }
-    { \tl_use:N \l_@@_tmpa_tl }
-    \tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin
+    \tl_gset_eq:NN \g_@@_output_tl \pgfpointorigin
   }
+  
   \group_end:
   \use:c {pgf at process}{%
-    \tl_use:N \g_@@_smuggle_tl
+    \tl_use:N \g_@@_output_tl
     \pgftransforminvert
     \use:c {pgf at pos@transform at glob}
   }
+  \tl_gclear:N \g_@@_output_tl
 }
 
 \ExplSyntaxOff
@@ -8281,6 +10232,7 @@
 \bool_new:N \l_@@_append_next_bool
 \bool_new:N \l_@@_skip_bool
 \bool_new:N \l_@@_save_bool
+\bool_new:N \l_@@_debugging_bool
 
 \seq_new:N \g_@@_nodes_seq
 
@@ -8417,6 +10369,14 @@
     \bool_set_true:N \l_@@_draft_bool
     \bool_set_true:N \l_@@_super_draft_bool
   },
+  debug/.is~ choice,
+  debug/true/.code={
+    \bool_set_true:N \l_@@_debugging_bool
+  },
+  debug/false/.code={
+    \bool_set_false:N \l_@@_debugging_bool
+  },
+  debug/.default=true,
   draft/.is~ family,
   draft,
   crossing~ label/.style={
@@ -8440,10 +10400,26 @@
 }
 %    \end{macrocode}
 %
+% \begin{macro}[internal]{\knot_debug:n}
+% Debugging
+%    \begin{macrocode}
+\cs_new_nopar:Npn \knot_debug:n #1
+{
+  \bool_if:NT \l_@@_debugging_bool
+  {
+    \iow_term:n {===Knot~ debug: #1===}
+  }
+}
+
+\cs_generate_variant:Nn \knot_debug:n {x}
+%    \end{macrocode}
+% \end{macro}
+%
 % Wrapper around \Verb+\tikzset+ for applying keys from a token list, checking for if the given token list exists.
 %    \begin{macrocode}
 \cs_new_nopar:Npn \knot_apply_style:N #1
 {
+  \knot_debug:n {knot~ apply~ style}
   \tl_if_exist:NT #1 {
     \exp_args:NV \tikzset #1
   }
@@ -8492,6 +10468,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_initialise:n #1
 {
+  \knot_debug:n {knot~ initialise}
   \tikzset{knot~ diagram/.cd,every~ knot~ diagram/.try,#1}
   \int_zero:N \l_@@_strands_int
   \tl_clear:N \l_@@_redraws_tl
@@ -8505,6 +10482,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_render:
 {
+  \knot_debug:n {knot~ render}
 %    \end{macrocode}
 % Start a scope and reset the transformation (since all transformations have already been taken into account when defining the strands).
 %    \begin{macrocode}
@@ -8591,6 +10569,8 @@
 % Close the scope
 %    \begin{macrocode}
   \endpgfscope
+  \knot_debug:x {knot~rendered,
+    ~found~\int_use:N  \g_@@_intersections_int \c_space_tl~intersections}
 }
 %    \end{macrocode}
 % \end{macro}
@@ -8600,6 +10580,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_draw_strand:n #1
 {
+  \knot_debug:n {knot~ draw~ strand~ #1}
   \pgfscope
   \group_begin:
   \spath_bake_round:c {knot strand #1}
@@ -8609,7 +10590,7 @@
   {
     ,
     knot~ diagram/only~ when~ rendering/.try,
-    only~ when~ rendering/.try
+    only~ when~ rendering/.try,
   }
   \spath_tikz_path:Vv \l_@@_tmpa_tl {knot strand #1}
   \group_end:
@@ -8625,6 +10606,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_draw_labels:n #1
 {
+  \knot_debug:n {knot~ draw~ labels}
   \bool_if:NT \l_@@_draft_bool
   {
     \spath_finalpoint:Nv \l_@@_tmpb_tl {knot strand #1}
@@ -8665,6 +10647,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_split_self_intersects:N #1
 {
+  \knot_debug:n {knot~ split~ self~ intersects}
   \tl_set:Nx \l_@@_tmpc_tl {\tl_item:nn {#1} {4}}
   \tl_case:NnF \l_@@_tmpc_tl
   {
@@ -8702,9 +10685,11 @@
       }
       {
         \fp_set:Nn \l_@@_tmpa_fp {.5 * \l_@@_tmpa_fp / \l_@@_tmpb_fp}
-        \fp_compare:nTF
+        \bool_if:nTF
         {
-          0 < \l_@@_tmpa_fp && \l_@@_tmpa_fp < 1
+          \fp_compare_p:n {0 < \l_@@_tmpa_fp}
+          && 
+          \fp_compare_p:n {\l_@@_tmpa_fp < 1}
         }
         {
           \spath_split_curve:NNnV
@@ -8758,6 +10743,8 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_intersections:nn #1#2
 {
+  \knot_debug:x {knot~ intersections~ between~
+    \l_@@_prefix_tl \c_space_tl #1~ and~ #2}
   \group_begin:
   \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_prefix_tl
   \tl_put_right:Nn \l_@@_tmpa_tl {#1}
@@ -8789,6 +10776,7 @@
 
   }
 
+  \knot_debug:x {found~\pgfintersectionsolutions\c_space_tl~ intersections}
   \int_compare:nT {\pgfintersectionsolutions > 0}
   {
     \int_step_function:nnnN
@@ -8808,6 +10796,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_save_intersections:nn #1#2
 {
+  \knot_debug:n {knot~ save~ intersections}
   \bool_if:NT \l_@@_save_bool
   {
     \tl_clear:N \l_@@_aux_tl
@@ -8861,6 +10850,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_do_intersection:n #1
 {
+  \knot_debug:n {knot~ do~ intersection~ #1}
 %    \end{macrocode}
 % Get the intersection coordinates.
 %    \begin{macrocode}
@@ -8867,6 +10857,8 @@
   \pgfpointintersectionsolution{#1}
   \dim_set:Nn \l_@@_tmpa_dim {\pgf at x}
   \dim_set:Nn \l_@@_tmpb_dim {\pgf at y}
+  \knot_debug:x {intersection~at~
+    (\dim_use:N \l_@@_tmpa_dim,\dim_use:N \l_@@_tmpb_dim)}
 %    \end{macrocode}
 % If we're dealing with filaments, we can get false positives from the end points.
 %    \begin{macrocode}
@@ -8925,8 +10917,9 @@
 %    \begin{macrocode}
   \bool_if:NF \l_@@_skip_bool
   {
-
+    
     \int_gincr:N \g_@@_intersections_int
+    \knot_debug:x {Processing~intersection~\int_use:N \g_@@_intersections_int}
 %    \end{macrocode}
 % This is the intersection test.
 % If the intersection finder finds too many, it might be useful to ignore some.
@@ -9007,6 +11000,8 @@
             !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl}
           }
           {
+            \knot_debug:x {Prepending~
+              \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}}
             \spath_prepend_no_move:cv
             {knot \tl_use:N \l_@@_prefix_tl -1}
             {knot \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}}
@@ -9017,9 +11012,13 @@
             {
               \l_@@_splits_bool
               &&
-              \tl_if_exist_p:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+              \tl_if_exist_p:c {knot previous
+                \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+              }
               &&
-              !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+              !\tl_if_empty_p:c {knot previous
+                \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+              }
             }
             {
               \knot_test_endpoint:NvnT
@@ -9027,6 +11026,11 @@
               {knot previous \tl_use:N \l_@@_tmpg_tl}
               {initial point}
               {
+                \knot_debug:x {Prepending~
+                  \tl_use:c {knot previous
+                    \tl_use:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+                  }
+                }
                 \spath_prepend_no_move:cv
                 {knot \tl_use:N \l_@@_prefix_tl -1}
                 {knot \tl_use:c
@@ -9034,10 +11038,12 @@
                     {knot previous \tl_use:N \l_@@_tmpg_tl}
                   }
                 }
-                \tl_set_eq:Nc \l_@@_tmpa_tl {knot \tl_use:N \l_@@_prefix_tl -1}
+                \tl_set_eq:Nc \l_@@_tmpa_tl
+                {knot \tl_use:N \l_@@_prefix_tl -1}
               }
             }
           }
+
 %    \end{macrocode}
 % Now the same for appending.
 %    \begin{macrocode}
@@ -9047,9 +11053,11 @@
             &&
             \tl_if_exist_p:c {knot next \tl_use:N \l_@@_tmpg_tl}
             &&
-            !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+            !\tl_if_empty_p:c {knot next \tl_use:N \l_@@_tmpg_tl}
           }
           {
+            \knot_debug:x {Appending~
+              \tl_use:c {knot next \tl_use:N \l_@@_tmpg_tl}}
             \spath_append_no_move:cv
             {knot \tl_use:N \l_@@_prefix_tl -1}
             {knot \tl_use:c {knot next \tl_use:N \l_@@_tmpg_tl}}
@@ -9057,17 +11065,25 @@
             {
               \l_@@_splits_bool
               &&
-              \tl_if_exist_p:c {knot previous \tl_use:N
-                \l_@@_tmpg_tl}
+              \tl_if_exist_p:c {knot next \tl_use:c { knot next \tl_use:N
+                \l_@@_tmpg_tl}}
               &&
-              !\tl_if_empty_p:c {knot previous \tl_use:N \l_@@_tmpg_tl}
+              !\tl_if_empty_p:c {knot next
+                \tl_use:c { knot next \tl_use:N \l_@@_tmpg_tl}
+              }
             }
             {
+              \knot_debug:x {Testing~ whether~ to~ append~
+                {knot next \tl_use:c { knot next \tl_use:N \l_@@_tmpg_tl}}
+              }
               \knot_test_endpoint:NvnT
               \l_@@_redraw_tolerance_dim
-              {knot previous \tl_use:N \l_@@_tmpg_tl}
+              {knot next \tl_use:N \l_@@_tmpg_tl}
               {final point}
               {
+                \knot_debug:x {Appending~
+                  {knot next \tl_use:c { knot next \tl_use:N \l_@@_tmpg_tl}}
+                }
                 \spath_append_no_move:cv
                 {knot \tl_use:N \l_@@_prefix_tl -1}
                 {knot \tl_use:c
@@ -9170,6 +11186,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_draw_crossing:nnn #1#2#3
 {
+  \knot_debug:n {knot~ draw~ crossing}
   \group_begin:
   \pgfscope
   \path[knot~ diagram/background~ clip] (#2, #3)
@@ -9224,6 +11241,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_split_strands:
 {
+  \knot_debug:n {knot~ split~ strands}
   \int_gzero:N \g_@@_filaments_int
   \int_step_function:nnnN {1} {1} {\l_@@_strands_int} \knot_split_strand:n
   \int_step_function:nnnN {1} {1} {\g_@@_filaments_int} \knot_compute_nexts:n
@@ -9237,6 +11255,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_compute_nexts:n #1
 {
+  \knot_debug:n {knot~ compute~ nexts}
   \tl_clear_new:c {knot next \tl_use:c {knot previous filament #1}}
   \tl_set:cn {knot next \tl_use:c {knot previous filament #1}} {filament #1}
 }
@@ -9248,6 +11267,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_split_strand:n #1
 {
+  \knot_debug:n {knot~ split~ strand}
   \int_set_eq:NN \l_@@_component_start_int \g_@@_filaments_int
   \int_incr:N \l_@@_component_start_int
   \tl_set_eq:Nc \l_@@_tmpa_tl {l_@@_options_strand #1}
@@ -9262,6 +11282,7 @@
 %    \begin{macrocode}
 \cs_new_protected_nopar:Npn \knot_save_filament:N #1
 {
+  \knot_debug:n {knot~ save~ filament}
   \tl_set:Nx \l_@@_tmpb_tl {\tl_item:nn {#1} {4}}
   \tl_case:NnF \l_@@_tmpb_tl
   {

Modified: trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/tex/latex/spath3/spath3.sty	2022-10-26 19:59:14 UTC (rev 64818)
@@ -15,7 +15,7 @@
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{expl3}
 \RequirePackage{pgf}
-\ProvidesExplPackage {spath3} {2021/02/21} {2.4} {Functions for
+\ProvidesExplPackage {spath3} {2022/08/24} {2.7} {Functions for
 manipulating PGF soft paths}
 \RequirePackage{xparse}
 \cs_new_protected:Nn \__spath_tl_put_right_braced:Nn
@@ -64,6 +64,9 @@
 \fp_new:N \l__spath_tmpa_fp
 \fp_new:N \l__spath_tmpb_fp
 \fp_new:N \l__spath_tmpc_fp
+\fp_new:N \l__spath_tmpd_fp
+\fp_new:N \l__spath_tmpe_fp
+\fp_new:N \l__spath_tmpf_fp
 
 \int_new:N \l__spath_tmpa_int
 \int_new:N \l__spath_tmpb_int
@@ -72,6 +75,11 @@
 \dim_new:N \l__spath_move_x_dim
 \dim_new:N \l__spath_move_y_dim
 \bool_new:N \l__spath_closed_bool
+\dim_new:N \l__spath_rectx_dim
+\dim_new:N \l__spath_recty_dim
+
+\bool_new:N \l__spath_rect_bool
+\bool_new:N \l_spath_movetorelevant_bool
 \tl_new:N \l__spath_intersecta_tl
 \tl_new:N \l__spath_intersectb_tl
 \tl_const:Nn \c_spath_moveto_tl {\pgfsyssoftpath at movetotoken}
@@ -80,8 +88,22 @@
 \tl_const:Nn \c_spath_curvetoa_tl {\pgfsyssoftpath at curvetosupportatoken}
 \tl_const:Nn \c_spath_curvetob_tl {\pgfsyssoftpath at curvetosupportbtoken}
 \tl_const:Nn \c_spath_closepath_tl {\pgfsyssoftpath at closepathtoken}
+\tl_const:Nn \c_spath_rectcorner_tl {\pgfsyssoftpath at rectcornertoken}
+\tl_const:Nn \c_spath_rectsize_tl {\pgfsyssoftpath at rectsizetoken}
 \int_new:N \g__spath_anon_int
 \int_gzero:N \g__spath_anon_int
+\cs_new_protected_nopar:Npn \spath_anonymous:N #1
+{
+  \tl_set:Nx #1 {anonymous_\int_use:N \g__spath_anon_int}
+  \int_gincr:N \g__spath_anon_int
+}
+\cs_new_protected_nopar:Npn \spath_ganonymous:N #1
+{
+  \tl_gset:Nx #1 {anonymous_\int_use:N \g__spath_anon_int}
+  \int_gincr:N \g__spath_anon_int
+}
+\cs_generate_variant:Nn \spath_anonymous:N {c}
+\cs_generate_variant:Nn \spath_ganonymous:N {c}
 \msg_new:nnn { spath3 } { unknown path construction }
 { The~ path~ construction~ element~ #1~ is~ not~ currently~ supported.}
 \cs_new_protected_nopar:Npn \__spath_segments_to_seq:n #1
@@ -169,6 +191,27 @@
 
       }
 
+      \c_spath_rectcorner_tl
+      {
+        \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_rectcorner_tl
+
+        \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+        \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+        \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+        \tl_put_right:Nx \l__spath_tmpb_tl {{\tl_head:N \l__spath_tmpa_tl}}
+        \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+      }
+
       \c_spath_closepath_tl
       {
         \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_moveto_tl
@@ -235,9 +278,11 @@
   \group_begin:
   \tl_set:Nn \l__spath_tmpa_tl {#1}
   \seq_clear:N \l__spath_tmpa_seq
+  \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
   \tl_put_right:NV \l__spath_tmpa_tl \c_spath_moveto_tl
-  \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_moveto_tl
+
   \bool_do_until:nn {
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
@@ -248,6 +293,11 @@
       \seq_put_right:NV \l__spath_tmpa_seq \l__spath_tmpb_tl
       \tl_clear:N \l__spath_tmpb_tl
     }
+    \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+    {
+      \seq_put_right:NV \l__spath_tmpa_seq \l__spath_tmpb_tl
+      \tl_clear:N \l__spath_tmpb_tl
+    }
     \tl_if_single:NTF \l__spath_tmpc_tl
     {
       \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl
@@ -310,6 +360,7 @@
       \c_spath_lineto_tl {}
       \c_spath_curveto_tl {}
       \c_spath_closepath_tl {}
+      \c_spath_rectsize_tl {}
     }
     {
       \int_incr:N \l__spath_tmpa_int
@@ -345,6 +396,10 @@
       {
         \int_incr:N \l__spath_tmpa_int
       }
+      \c_spath_rectcorner_tl
+      {
+        \int_incr:N \l__spath_tmpa_int
+      }
     }
   }
   \int_gzero:N \g__spath_output_int
@@ -397,11 +452,36 @@
   \tl_set:Nn \l__spath_tmpa_tl {#1}
   \tl_reverse:N \l__spath_tmpa_tl
   \tl_clear:N \l__spath_tmpb_tl
-  \tl_set:Nx \l__spath_tmpb_tl
+  \tl_set:Nx \l__spath_tmpc_tl {\tl_item:Nn \l__spath_tmpa_tl {3}}
+  \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectsize_tl
   {
-    { \tl_item:Nn \l__spath_tmpa_tl {2} }
-    { \tl_item:Nn \l__spath_tmpa_tl {1} }
+    \tl_set:Nx \l__spath_tmpb_tl
+    {
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l__spath_tmpa_tl {2}
+          +
+          \tl_item:Nn \l__spath_tmpa_tl {5}
+        }
+      }
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l__spath_tmpa_tl {1}
+          +
+          \tl_item:Nn \l__spath_tmpa_tl {4}
+        }
+      }
+    }
   }
+  {
+    \tl_set:Nx \l__spath_tmpb_tl
+    {
+      { \tl_item:Nn \l__spath_tmpa_tl {2} }
+      { \tl_item:Nn \l__spath_tmpa_tl {1} }
+    }
+  }
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
   \group_end:
 }
@@ -440,6 +520,16 @@
           { \tl_item:Nn \l__spath_tmpa_tl {3} }
         }
       }
+
+      \c_spath_rectcorner_tl
+      {
+        \tl_set:Nx \l__spath_tmpc_tl
+        {
+          { \tl_item:Nn \l__spath_tmpa_tl {2} }
+          { \tl_item:Nn \l__spath_tmpa_tl {3} }
+        }
+      }
+
     }
     \prg_replicate:nn {3}
     {
@@ -463,114 +553,371 @@
   \tl_gclear:N \g__spath_output_tl
 }
 \cs_generate_variant:Nn \spath_gfinalmovepoint:Nn {NV, cn, cV}
-\cs_new_protected_nopar:Npn \__spath_reverse:n #1
+\cs_new_protected_nopar:Npn \__spath_initialtangent:n #1
 {
   \group_begin:
+  \tl_set:Nx \l__spath_tmpb_tl {\tl_item:nn {#1} {4}}
+  \tl_if_eq:NNTF \l__spath_tmpb_tl \c_spath_curvetoa_tl
+  {
+    \fp_set:Nn \l__spath_tmpa_fp {3}
+  }
+  {
+    \fp_set:Nn \l__spath_tmpa_fp {1}
+  }
+  \tl_clear:N \l__spath_tmpa_tl
+  \tl_set:Nx \l__spath_tmpa_tl
+  {
+    {
+      \fp_to_dim:n {
+        \l__spath_tmpa_fp
+        *
+        (
+        \tl_item:nn {#1} {5}
+        -
+        \tl_item:nn {#1} {2}
+        )
+      }
+    }
+    {
+      \fp_to_dim:n {
+        \l__spath_tmpa_fp
+        *
+        (
+        \tl_item:nn {#1} {6}
+        -
+        \tl_item:nn {#1} {3}
+        )
+      }
+    }
+  }
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_initialtangent:Nn #1#2
+{
+  \__spath_initialtangent:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_initialtangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \spath_ginitialtangent:Nn #1#2
+{
+  \__spath_initialtangent:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_ginitialtangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \__spath_finaltangent:n #1
+{
+  \group_begin:
   \tl_set:Nn \l__spath_tmpa_tl {#1}
-
+  \tl_reverse:N \l__spath_tmpa_tl
+  \tl_set:Nx \l__spath_tmpb_tl {\tl_item:nn {#1} {6}}
+  \tl_if_eq:NNTF \l__spath_tmpb_tl \c_spath_curveto_tl
+  {
+    \fp_set:Nn \l__spath_tmpa_fp {3}
+  }
+  {
+    \fp_set:Nn \l__spath_tmpa_fp {1}
+  }
   \tl_clear:N \l__spath_tmpb_tl
-  \tl_clear:N \l__spath_tmpd_tl
-  \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-  \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
-  \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-  \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
-  \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-
-  \tl_put_left:Nx \l__spath_tmpd_tl
+  \tl_set:Nx \l__spath_tmpb_tl
   {
-    {\dim_use:N \l__spath_tmpa_dim}
-    {\dim_use:N \l__spath_tmpb_dim}
+    {
+      \fp_to_dim:n {
+        \l__spath_tmpa_fp
+        *
+        (
+        \tl_item:Nn \l__spath_tmpa_tl {2}
+        -
+        \tl_item:Nn \l__spath_tmpa_tl {5}
+        )
+      }
+    }
+    {
+      \fp_to_dim:n {
+        \l__spath_tmpa_fp
+        *
+        (
+        \tl_item:Nn \l__spath_tmpa_tl {1}
+        -
+        \tl_item:Nn \l__spath_tmpa_tl {4}
+        )
+      }
+    }
   }
-
-  \bool_set_false:N \l__spath_closed_bool
-
-  \bool_until_do:nn {
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_finaltangent:Nn #1#2
+{
+  \__spath_finaltangent:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_finaltangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \spath_gfinaltangent:Nn #1#2
+{
+  \__spath_finaltangent:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gfinaltangent:Nn {NV, cn, cV, Nv}
+\cs_new_protected_nopar:Npn \__spath_finalmovetangent:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpc_tl { {0pt} {0pt} }
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \bool_do_until:nn
+  {
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
   {
-    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
-
-    \tl_case:NnTF \l__spath_tmpc_tl
+    \tl_set:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
+    \tl_case:Nn \l__spath_tmpb_tl
     {
-      \c_spath_moveto_tl {
-
-        \bool_if:NT \l__spath_closed_bool
+      \c_spath_moveto_tl
+      {
+        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:Nn \l__spath_tmpa_tl {4} }
+        \tl_if_eq:NNTF \l__spath_tmpd_tl \c_spath_curveto_tl
         {
-          \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl
-          \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl}
-          \tl_put_right:Nx \l__spath_tmpd_tl
+          \fp_set:Nn \l__spath_tmpa_fp {3}
+        }
+        {
+          \fp_set:Nn \l__spath_tmpa_fp {1}
+        }
+        \tl_set:Nx \l__spath_tmpc_tl
+        {
           {
-            { \tl_head:N \l__spath_tmpd_tl }
-            { \tl_head:N \l__spath_tmpe_tl }
+            \fp_to_dim:n
+            {
+              \l__spath_tmpa_fp
+              *
+              (
+              \tl_item:Nn \l__spath_tmpa_tl {5}
+              -
+              \tl_item:Nn \l__spath_tmpa_tl {2}
+              )
+            }
           }
+          {
+            \fp_to_dim:n
+            {
+              \l__spath_tmpa_fp
+              *
+              (
+              \tl_item:Nn \l__spath_tmpa_tl {6}
+              -
+              \tl_item:Nn \l__spath_tmpa_tl {3}
+              )
+            }
+          }
         }
-        \bool_set_false:N \l__spath_closed_bool
-        \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl
-        \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
-        \tl_clear:N \l__spath_tmpd_tl
       }
-      \c_spath_lineto_tl {
-        \tl_put_left:NV \l__spath_tmpd_tl \c_spath_lineto_tl
-      }
-      \c_spath_curveto_tl {
-        \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetoa_tl
-      }
-      \c_spath_curvetoa_tl {
-        \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curveto_tl
-      }
-      \c_spath_curvetob_tl {
-        \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetob_tl
-      }
     }
+    \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_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_finalmovetangent:Nn #1#2
+{
+  \__spath_finalmovetangent:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_finalmovetangent:Nn {NV, cn, cV}
+\cs_new_protected_nopar:Npn \spath_gfinalmovetangent:Nn #1#2
+{
+  \__spath_finalmovetangent:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gfinalmovetangent:Nn {NV, cn, cV}
+\cs_new_protected_nopar:Npn \__spath_reverse:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
 
-      \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+  \tl_clear:N \l__spath_tmpb_tl
+  \tl_clear:N \l__spath_tmpd_tl
+
+  \bool_set_false:N \l__spath_rect_bool
+
+  \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+  \bool_while_do:nn {
+    \tl_if_eq_p:NN \l__spath_tmpc_tl \c_spath_rectcorner_tl
+  }
+  {
+    \tl_put_left:Nx \l__spath_tmpd_tl
+    {
+      \tl_item:Nn \l__spath_tmpa_tl {1}
+      {\tl_item:Nn \l__spath_tmpa_tl {2}}
+      {\tl_item:Nn \l__spath_tmpa_tl {3}}
+      \tl_item:Nn \l__spath_tmpa_tl {4}
+      {\tl_item:Nn \l__spath_tmpa_tl {5}}
+      {\tl_item:Nn \l__spath_tmpa_tl {6}}
+    }
+    \prg_replicate:nn {6}
+    {
       \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-      \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
-      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+    \bool_set_true:N \l__spath_rect_bool
+  }
 
-      \tl_put_left:Nx \l__spath_tmpd_tl
-      {
-        {\dim_use:N \l__spath_tmpa_dim}
-        {\dim_use:N \l__spath_tmpb_dim}
-      }
+  \tl_if_empty:NF \l__spath_tmpa_tl
+  {
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
+    \tl_put_left:Nx \l__spath_tmpd_tl
+    {
+      {\dim_use:N \l__spath_tmpa_dim}
+      {\dim_use:N \l__spath_tmpb_dim}
     }
+
+    \bool_set_false:N \l__spath_closed_bool
+
+    \bool_until_do:nn {
+      \tl_if_empty_p:N \l__spath_tmpa_tl
+    }
     {
-      \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_closepath_tl
+      \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+      \bool_set_false:N \l__spath_rect_bool
+
+      \tl_case:NnTF \l__spath_tmpc_tl
       {
-        \bool_set_true:N \l__spath_closed_bool
+        \c_spath_moveto_tl {
+
+          \bool_if:NT \l__spath_closed_bool
+          {
+            \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl
+            \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl}
+            \tl_put_right:Nx \l__spath_tmpd_tl
+            {
+              { \tl_head:N \l__spath_tmpd_tl }
+              { \tl_head:N \l__spath_tmpe_tl }
+            }
+          }
+          \bool_set_false:N \l__spath_closed_bool
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl
+          \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+          \tl_clear:N \l__spath_tmpd_tl
+        }
+        \c_spath_rectcorner_tl {
+
+          \bool_if:NT \l__spath_closed_bool
+          {
+            \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl
+            \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl}
+            \tl_put_right:Nx \l__spath_tmpd_tl
+            {
+              { \tl_head:N \l__spath_tmpd_tl }
+              { \tl_head:N \l__spath_tmpe_tl }
+            }
+          }
+          \bool_set_false:N \l__spath_closed_bool
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl
+          \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+          \tl_clear:N \l__spath_tmpd_tl
+
+          \bool_while_do:nn {
+            \tl_if_eq_p:NN \l__spath_tmpc_tl \c_spath_rectcorner_tl
+          }
+          {
+            \tl_put_left:Nx \l__spath_tmpb_tl
+            {
+              \tl_item:Nn \l__spath_tmpa_tl {1}
+              {\tl_item:Nn \l__spath_tmpa_tl {2}}
+              {\tl_item:Nn \l__spath_tmpa_tl {3}}
+              \tl_item:Nn \l__spath_tmpa_tl {4}
+              {\tl_item:Nn \l__spath_tmpa_tl {5}}
+              {\tl_item:Nn \l__spath_tmpa_tl {6}}
+            }
+            \prg_replicate:nn {6}
+            {
+              \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+            }
+            \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+          }
+          \bool_set_true:N \l__spath_rect_bool
+
+        }
+        \c_spath_lineto_tl {
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_lineto_tl
+        }
+        \c_spath_curveto_tl {
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetoa_tl
+        }
+        \c_spath_curvetoa_tl {
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curveto_tl
+        }
+        \c_spath_curvetob_tl {
+          \tl_put_left:NV \l__spath_tmpd_tl \c_spath_curvetob_tl
+        }
       }
       {
-        \msg_warning:nnx
-        { spath3 }
-        { unknown path construction }
-        {\l__spath_tmpc_tl }
+        \tl_if_empty:NF \l__spath_tmpa_tl
+        {
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+        \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+        \tl_put_left:Nx \l__spath_tmpd_tl
+        {
+          {\dim_use:N \l__spath_tmpa_dim}
+          {\dim_use:N \l__spath_tmpb_dim}
+        }
+        }
       }
+      {
+        \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_closepath_tl
+        {
+          \bool_set_true:N \l__spath_closed_bool
+        }
+        {
+          \msg_warning:nnx
+          { spath3 }
+          { unknown path construction }
+          { \l__spath_tmpc_tl }
+        }
 
-      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+        \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
+      }
     }
-  }
 
-  \bool_if:NT \l__spath_closed_bool
-  {
-    \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl
-    \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl}
-    \tl_put_right:Nx \l__spath_tmpd_tl
+    \bool_if:NT \l__spath_closed_bool
     {
-      { \tl_head:N \l__spath_tmpd_tl }
-      { \tl_head:N \l__spath_tmpe_tl }
+      \tl_put_right:NV \l__spath_tmpd_tl \c_spath_closepath_tl
+      \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpd_tl}
+      \tl_put_right:Nx \l__spath_tmpd_tl
+      {
+        { \tl_head:N \l__spath_tmpd_tl }
+        { \tl_head:N \l__spath_tmpe_tl }
+      }
     }
+
+    \bool_set_false:N \l__spath_closed_bool
+    \bool_if:NF \l__spath_rect_bool
+    {
+      \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl
+    }
   }
 
-  \bool_set_false:N \l__spath_closed_bool
-  \tl_put_left:NV \l__spath_tmpd_tl \c_spath_moveto_tl
   \tl_put_left:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
-
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
   \group_end:
 }
@@ -602,15 +949,22 @@
 {
   \group_begin:
   \tl_clear:N \l__spath_tmpa_tl
-  \int_compare:nT
+  \tl_set:Nx \l__spath_tmpb_tl {\tl_head:n {#1}}
+  \tl_if_eq:NNTF \l__spath_tmpb_tl \c_spath_rectcorner_tl
   {
-    \tl_count:n {#1} > 3
+    \tl_set_eq:NN \l__spath_tmpa_tl \c_spath_rectcorner_tl
   }
   {
-    \tl_set:Nx \l__spath_tmpa_tl
+    \int_compare:nT
     {
-      \tl_item:Nn {#1} {4}
+      \tl_count:n {#1} > 3
     }
+    {
+      \tl_set:Nx \l__spath_tmpa_tl
+      {
+        \tl_item:Nn {#1} {4}
+      }
+    }
   }
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
   \group_end:
@@ -648,6 +1002,10 @@
     {
       \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_curveto_tl
     }
+    \tl_if_eq:NNT \l__spath_tmpb_tl \c_spath_rectsize_tl
+    {
+      \tl_set_eq:NN \l__spath_tmpb_tl \c_spath_rectcorner_tl
+    }
   }
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
   \group_end:
@@ -670,22 +1028,60 @@
 {
   \group_begin:
   \tl_set:Nn \l__spath_tmpa_tl {#1}
+
+  \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
   \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
   \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+  \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+  {
+    \dim_set_eq:NN \l__spath_rectx_dim \l__spath_tmpa_dim
+    \dim_set_eq:NN \l__spath_recty_dim \l__spath_tmpb_dim
+  }
   \bool_until_do:nn {
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
   {
+    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-    \dim_set:Nn \l__spath_tmpa_dim
-    {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
-    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-    \dim_set:Nn \l__spath_tmpb_dim
-    {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
-    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l__spath_tmpa_dim
+      {\dim_min:nn
+        {\tl_head:N \l__spath_tmpa_tl + \l__spath_rectx_dim} {\l__spath_tmpa_dim}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+      \dim_set:Nn \l__spath_tmpb_dim
+      {\dim_min:nn
+        {\tl_head:N \l__spath_tmpa_tl + \l__spath_recty_dim} {\l__spath_tmpb_dim}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l__spath_tmpa_dim
+      {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
+      \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l__spath_rectx_dim {\tl_head:N \l__spath_tmpa_tl}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+      \dim_set:Nn \l__spath_tmpb_dim
+      {\dim_min:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
+      \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l__spath_recty_dim {\tl_head:N \l__spath_tmpa_tl}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+
   }
   \tl_clear:N \l__spath_tmpb_tl
   \tl_put_right:Nx \l__spath_tmpb_tl
@@ -714,25 +1110,63 @@
 {
   \group_begin:
   \tl_set:Nn \l__spath_tmpa_tl {#1}
+
+  \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
   \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
   \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
   \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+  \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+  {
+    \dim_set_eq:NN \l__spath_rectx_dim \l__spath_tmpa_dim
+    \dim_set_eq:NN \l__spath_recty_dim \l__spath_tmpb_dim
+  }
   \bool_until_do:nn {
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
   {
+    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-    \dim_set:Nn \l__spath_tmpa_dim
-    {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
-    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
-    \dim_set:Nn \l__spath_tmpb_dim
-    {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
-    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l__spath_tmpa_dim
+      {\dim_max:nn
+        {\tl_head:N \l__spath_tmpa_tl + \l__spath_rectx_dim} {\l__spath_tmpa_dim}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+      \dim_set:Nn \l__spath_tmpb_dim
+      {\dim_max:nn
+        {\tl_head:N \l__spath_tmpa_tl + \l__spath_recty_dim} {\l__spath_tmpb_dim}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l__spath_tmpa_dim
+      {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpa_dim}}
+      \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l__spath_rectx_dim {\tl_head:N \l__spath_tmpa_tl}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+
+      \dim_set:Nn \l__spath_tmpb_dim
+      {\dim_max:nn {\tl_head:N \l__spath_tmpa_tl} {\l__spath_tmpb_dim}}
+      \tl_if_eq:NNT \l__spath_tmpc_tl \c_spath_rectcorner_tl
+      {
+        \dim_set:Nn \l__spath_recty_dim {\tl_head:N \l__spath_tmpa_tl}
+      }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    }
+
   }
   \tl_clear:N \l__spath_tmpb_tl
-  \tl_put_right:Nx \l__spath_tmpb_tl
+  \tl_set:Nx \l__spath_tmpb_tl
   {
     {\dim_use:N \l__spath_tmpa_dim}
     {\dim_use:N \l__spath_tmpb_dim}
@@ -762,7 +1196,7 @@
     \tl_clear:N \l__spath_tmpa_tl
     \tl_put_right:Nn \l__spath_tmpa_tl {
       \ExplSyntaxOn
-      \tl_clear:N #1
+      \tl_clear_new:N #1
       \tl_set:Nn #1 {#2}
       \ExplSyntaxOff
     }
@@ -780,6 +1214,7 @@
     \spath_save_to_aux:NV #1#1
   }
 }
+\cs_generate_variant:Nn \spath_save_to_aux:N {c}
 \cs_new_protected_nopar:Npn \__spath_translate:nnn #1#2#3
 {
   \group_begin:
@@ -789,13 +1224,27 @@
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
   {
+    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
+
     \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
-    \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl + #2}
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l__spath_tmpa_dim {\tl_head:N \l__spath_tmpa_tl + #2}
+    }
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
-    \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl + #3}
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectsize_tl
+    {
+      \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl}
+    }
+    {
+      \dim_set:Nn \l__spath_tmpb_dim {\tl_head:N \l__spath_tmpa_tl + #3}
+    }
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
     \tl_put_right:Nx \l__spath_tmpb_tl
@@ -969,6 +1418,8 @@
     \tl_if_empty_p:N \l__spath_tmpa_tl
   }
   {
+    \tl_set:Nx \l__spath_tmpe_tl {\tl_head:N \l__spath_tmpa_tl}
+
     \tl_put_right:Nx \l__spath_tmpb_tl {\tl_head:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl}
@@ -976,10 +1427,20 @@
     \tl_set:Nx \l__spath_tmpd_tl {\tl_head:N \l__spath_tmpa_tl}
     \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
 
-    \fp_set:Nn \l__spath_tmpa_fp
-    {\l__spath_tmpc_tl * #2 + \l__spath_tmpd_tl * #4 + #6}
-    \fp_set:Nn \l__spath_tmpb_fp
-    {\l__spath_tmpc_tl * #3 + \l__spath_tmpd_tl * #5 + #7}
+    \tl_if_eq:NNTF \l__spath_tmpe_tl \c_spath_rectsize_tl
+    {
+      \fp_set:Nn \l__spath_tmpa_fp
+      {\l__spath_tmpc_tl * #2 + \l__spath_tmpd_tl * #4}
+      \fp_set:Nn \l__spath_tmpb_fp
+      {\l__spath_tmpc_tl * #3 + \l__spath_tmpd_tl * #5}
+    }
+    {
+      \fp_set:Nn \l__spath_tmpa_fp
+      {\l__spath_tmpc_tl * #2 + \l__spath_tmpd_tl * #4 + #6}
+      \fp_set:Nn \l__spath_tmpb_fp
+      {\l__spath_tmpc_tl * #3 + \l__spath_tmpd_tl * #5 + #7}
+    }
+
     \tl_put_right:Nx \l__spath_tmpb_tl
     {
       {\fp_to_dim:N \l__spath_tmpa_fp}
@@ -1207,8 +1668,8 @@
 \cs_new_protected_nopar:Npn \__spath_splice_between:nnn #1#2#3
 {
   \group_begin:
-  \spath_finalpoint:NV \l__spath_tmpd_tl {#1}
-  \spath_initialpoint:NV \l__spath_tmpe_tl {#3}
+  \spath_finalpoint:Nn \l__spath_tmpd_tl {#1}
+  \spath_initialpoint:Nn \l__spath_tmpe_tl {#3}
   \spath_span:NnVV \l__spath_tmpb_tl {#2} \l__spath_tmpd_tl \l__spath_tmpe_tl
   \spath_append_no_move:NnV \l__spath_tmpa_tl {#1} \l__spath_tmpb_tl
   \spath_append_no_move:Nn \l__spath_tmpa_tl {#3}
@@ -1239,6 +1700,312 @@
   \spath_gsplice_between:NVnn #1#1{#2}{#3}
 }
 \cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
+\cs_new_protected_nopar:Npn \__spath_hobby_curve:nnnn #1#2#3#4
+{
+  \group_begin:
+  \fp_set:Nn \l__spath_tmpa_fp
+  {
+    (
+    (\tl_item:nn {#2} {1})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    +
+    (\tl_item:nn {#2} {2})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+  \fp_set:Nn \l__spath_tmpb_fp
+  {
+    (
+    -
+    (\tl_item:nn {#2} {1})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    +
+    (\tl_item:nn {#2} {2})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+  \fp_set:Nn \l__spath_tmpc_fp
+  {
+    (
+    (\tl_item:nn {#3} {1})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    +
+    (\tl_item:nn {#3} {2})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+  \fp_set:Nn \l__spath_tmpd_fp
+  {
+    (
+    (\tl_item:nn {#3} {1})
+    *
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})
+    -
+    (\tl_item:nn {#3} {2})
+    *
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})
+    )
+    /
+    sqrt
+    (
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    *
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    )
+  }
+
+  \fp_set:Nn \l__spath_tmpe_fp
+  {
+    (
+    2 + sqrt(2) *
+    (\l__spath_tmpb_fp - 1/16 * \l__spath_tmpd_fp)
+    *
+    (\l__spath_tmpd_fp - 1/16 * \l__spath_tmpb_fp)
+    *
+    (\l__spath_tmpa_fp - \l__spath_tmpc_fp)
+    )
+    /
+    (
+    1
+    +
+    (1 - (3 - sqrt(5))/2)
+    *
+    \l__spath_tmpa_fp
+    +
+    (3 - sqrt(5))/2
+    *
+    \l__spath_tmpc_fp
+    )
+    *
+    sqrt
+    (
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    /
+    (
+    (\tl_item:nn {#2} {1})^2
+    +
+    (\tl_item:nn {#2} {2})^2
+    )
+    )
+    /3
+  }
+  \fp_set:Nn \l__spath_tmpf_fp
+  {
+    (
+    2 - sqrt(2) *
+    (\l__spath_tmpb_fp - 1/16 * \l__spath_tmpd_fp)
+    *
+    (\l__spath_tmpd_fp - 1/16 * \l__spath_tmpb_fp)
+    *
+    (\l__spath_tmpa_fp - \l__spath_tmpc_fp)
+    )
+    /
+    (
+    1
+    +
+    (1 - (3 - sqrt(5))/2)
+    *
+    \l__spath_tmpc_fp
+    +
+    (3 - sqrt(5))/2
+    *
+    \l__spath_tmpa_fp
+    )
+    *
+    sqrt
+    (
+    (
+    (\tl_item:nn {#4} {1} - \tl_item:nn {#1} {1})^2
+    +
+    (\tl_item:nn {#4} {2} - \tl_item:nn {#1} {2})^2
+    )
+    /
+    (
+    (\tl_item:nn {#3} {1})^2
+    +
+    (\tl_item:nn {#3} {2})^2
+    )
+    )
+    /3
+  }
+
+  \tl_set:Nx \l__spath_tmpa_tl
+  {
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#1} {1}
+        +
+        \l__spath_tmpe_fp
+        *
+        (\tl_item:nn {#2} {1})
+      }
+    }
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#1} {2}
+        +
+        \l__spath_tmpe_fp
+        *
+        (\tl_item:nn {#2} {2})
+      }
+    }
+  }
+  \tl_set:Nx \l__spath_tmpb_tl
+  {
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#4} {1}
+        -
+        \l__spath_tmpf_fp
+        *
+        (\tl_item:nn {#3} {1})
+      }
+    }
+    {
+      \fp_to_dim:n
+      {
+        \tl_item:nn {#4} {2}
+        -
+        \l__spath_tmpf_fp
+        *
+        (\tl_item:nn {#3} {2})
+      }
+    }
+  }
+
+  \tl_clear:N \l__spath_tmpc_tl
+  \tl_set:NV \l__spath_tmpc_tl \c_spath_moveto_tl
+  \tl_put_right:Nn \l__spath_tmpc_tl {#1}
+  \tl_put_right:NV \l__spath_tmpc_tl \c_spath_curvetoa_tl
+  \tl_put_right:NV \l__spath_tmpc_tl \l__spath_tmpa_tl
+  \tl_put_right:NV \l__spath_tmpc_tl \c_spath_curvetob_tl
+  \tl_put_right:NV \l__spath_tmpc_tl \l__spath_tmpb_tl
+  \tl_put_right:NV \l__spath_tmpc_tl \c_spath_curveto_tl
+  \tl_put_right:Nn \l__spath_tmpc_tl {#4}
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_hobby_curve:Nnnnn #1#2#3#4#5
+{
+  \__spath_hobby_curve:nnnn {#2}{#3}{#4}{#5}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_hobby_curve:Nnnnn {NVVVV}
+\cs_new_protected_nopar:Npn \spath_ghobby_curve:Nnnnn #1#2#3#4#5
+{
+  \__spath_hobby_curve:nnnn {#2}{#3}{#4}{#5}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_ghobby_curve:Nnnnn {NVVVV}
+\cs_new_protected_nopar:Npn \__spath_curve_between:nn #1#2
+{
+  \group_begin:
+  \spath_finalpoint:Nn \l__spath_tmpa_tl {#1}
+  \spath_finaltangent:Nn \l__spath_tmpb_tl {#1}
+  \spath_initialpoint:Nn \l__spath_tmpc_tl {#2}
+  \spath_initialtangent:Nn \l__spath_tmpd_tl {#2}
+
+  \spath_hobby_curve:NVVVV \l__spath_tmpe_tl
+  \l__spath_tmpa_tl \l__spath_tmpb_tl \l__spath_tmpd_tl \l__spath_tmpc_tl
+
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \spath_append_no_move:NV \l__spath_tmpa_tl \l__spath_tmpe_tl
+  \spath_append_no_move:Nn \l__spath_tmpa_tl {#2}
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_curve_between:Nnn #1#2#3
+{
+  \__spath_curve_between:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_curve_between:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_curve_between:Nn #1#2
+{
+  \spath_curve_between:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_curve_between:Nn {NV, cn, cv}
+\cs_new_protected_nopar:Npn \spath_gcurve_between:Nnn #1#2#3
+{
+  \__spath_curve_between:nn {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gcurve_between:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gcurve_between:Nn #1#2
+{
+  \spath_gcurve_between:NVnn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gcurve_between:Nn {NV, cn, cv}
 \cs_new_protected_nopar:Npn \__spath_close_with:nn #1#2
 {
   \group_begin:
@@ -1295,6 +2062,68 @@
   \spath_gclose_with:NVn #1#1{#2}
 }
 \cs_generate_variant:Nn \spath_gclose_with:Nn {cn, cV, cv, NV}
+\cs_new_protected_nopar:Npn \__spath_close_with_curve:n #1
+{
+  \group_begin:
+  \spath_finalpoint:Nn \l__spath_tmpa_tl {#1}
+  \spath_finaltangent:Nn \l__spath_tmpb_tl {#1}
+  \spath_finalmovepoint:Nn \l__spath_tmpc_tl {#1}
+  \spath_finalmovetangent:Nn \l__spath_tmpd_tl {#1}
+  \dim_compare:nTF
+  {
+    \dim_abs:n
+    {
+      \tl_item:Nn \l__spath_tmpa_tl {1}
+      -
+      \tl_item:Nn \l__spath_tmpc_tl {1}
+    }
+    +
+    \dim_abs:n
+    {
+      \tl_item:Nn \l__spath_tmpa_tl {2}
+      -
+      \tl_item:Nn \l__spath_tmpc_tl {2}
+    }
+    < 0.01pt
+  }
+  {
+    \__spath_close:n {#1}
+  }
+  {
+
+    \spath_hobby_curve:NVVVV \l__spath_tmpe_tl
+    \l__spath_tmpa_tl \l__spath_tmpb_tl \l__spath_tmpd_tl \l__spath_tmpc_tl
+
+    \tl_set:Nn \l__spath_tmpa_tl {#1}
+    \spath_append_no_move:NV \l__spath_tmpa_tl \l__spath_tmpe_tl
+    \__spath_close:V \l__spath_tmpa_tl
+  }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_close_with_curve:Nn #1#2
+{
+  \__spath_close_with_curve:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_close_with_curve:Nn {cn, cV, cv, NV}
+\cs_new_protected_nopar:Npn \spath_close_with_curve:N #1
+{
+  \spath_close_with_curve:NV #1#1
+}
+\cs_generate_variant:Nn \spath_close_with_curve:N {c}
+\cs_new_protected_nopar:Npn \spath_gclose_with_curve:Nn #1#2
+{
+  \__spath_close_with_curve:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gclose_with_curve:Nn {cn, cV, cv, NV}
+\cs_new_protected_nopar:Npn \spath_gclose_with_curve:N #1
+{
+  \spath_gclose_with_curve:NV #1#1
+}
+\cs_generate_variant:Nn \spath_gclose_with_curve:N {c}
 \cs_new_protected_nopar:Npn \__spath_weld:nn #1#2
 {
   \group_begin:
@@ -1335,9 +2164,20 @@
   \group_begin:
   \tl_set:Nn \l__spath_tmpa_tl {#1}
   \tl_set:Nn \l__spath_tmpb_tl {#2}
-  \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
-  \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
-  \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+  \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpb_tl}
+  \spath_finalaction:Nn \l__spath_tmpd_tl {#1}
+  \bool_if:nT {
+    ! \tl_if_eq_p:NN \l__spath_tmpd_tl \c_spath_closepath_tl
+    &&
+    ! \tl_if_eq_p:NN \l__spath_tmpd_tl \c_spath_rectcorner_tl
+    &&
+    \tl_if_eq_p:NN \l__spath_tmpc_tl \c_spath_moveto_tl
+  }
+  {
+    \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+    \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+    \tl_set:Nx \l__spath_tmpb_tl {\tl_tail:N \l__spath_tmpb_tl}
+  }
 
   \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
@@ -1462,6 +2302,43 @@
   \spath_gbake_round:NV #1#1
 }
 \cs_generate_variant:Nn \spath_gbake_round:N {c}
+\cs_new_protected_nopar:Npn \__spath_bake_shorten:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \pgfsyssoftpath at getcurrentpath\l__spath_tmpb_tl
+  \pgfsyssoftpath at setcurrentpath\l__spath_tmpa_tl
+  \pgf at prepare@end at of@path
+  \pgf at prepare@start at of@path
+  \pgfsyssoftpath at getcurrentpath\l__spath_tmpa_tl
+  \pgfsyssoftpath at setcurrentpath\l__spath_tmpb_tl
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_bake_shorten:Nn #1#2
+{
+  \__spath_bake_shorten:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_bake_shorten:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_bake_shorten:N #1
+{
+  \spath_bake_shorten:NV #1#1
+}
+\cs_generate_variant:Nn \spath_bake_shorten:N {c}
+\cs_new_protected_nopar:Npn \spath_gbake_shorten:Nn #1#2
+{
+  \__spath_bake_shorten:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gbake_shorten:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_gbake_shorten:N #1
+{
+  \spath_gbake_shorten:NV #1#1
+}
+\cs_generate_variant:Nn \spath_gbake_shorten:N {c}
 \cs_new_protected_nopar:Npn \__spath_close:n #1
 {
   \group_begin:
@@ -1497,10 +2374,83 @@
   \spath_gclose:NV #1#1
 }
 \cs_generate_variant:Nn \spath_gclose:N {c}
+\cs_new_protected_nopar:Npn \__spath_adjust_close:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \spath_finalmovepoint:NV \l__spath_tmpb_tl \l__spath_tmpa_tl
+  \spath_finalpoint:NV \l__spath_tmpc_tl \l__spath_tmpa_tl
+  \tl_reverse:N \l__spath_tmpa_tl
+  \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+  \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+  \tl_set:Nx \l__spath_tmpd_tl {\tl_head:N \l__spath_tmpa_tl}
+  \tl_if_eq:NNT \l__spath_tmpd_tl \c_spath_curveto_tl
+  {
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    \tl_clear:N \l__spath_tmpe_tl
+    \tl_set:Nx \l__spath_tmpe_tl {
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l__spath_tmpa_tl {1}
+          -
+          \tl_item:Nn \l__spath_tmpc_tl {2}
+          +
+          \tl_item:Nn \l__spath_tmpb_tl {2}
+        }
+      }
+      {
+        \dim_eval:n
+        {
+          \tl_item:Nn \l__spath_tmpa_tl {2}
+          -
+          \tl_item:Nn \l__spath_tmpc_tl {1}
+          +
+          \tl_item:Nn \l__spath_tmpb_tl {1}
+        }
+      }
+    }
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl}
+    \tl_put_left:NV \l__spath_tmpa_tl \l__spath_tmpe_tl
+    \tl_put_left:NV \l__spath_tmpa_tl \l__spath_tmpd_tl
+  }
+  \tl_reverse:N \l__spath_tmpa_tl
+  \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+  \tl_put_right:NV \l__spath_tmpa_tl \c_spath_closepath_tl
+  \tl_put_right:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \__spath_adjust_close:n {V}
+\cs_new_protected_nopar:Npn \spath_adjust_close:Nn #1#2
+{
+  \__spath_adjust_close:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_adjust_close:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_adjust_close:N #1
+{
+  \spath_adjust_close:NV #1#1
+}
+\cs_generate_variant:Nn \spath_adjust_close:N {c}
+\cs_new_protected_nopar:Npn \spath_adjust_gclose:Nn #1#2
+{
+  \__spath_adjust_close:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_adjust_gclose:Nn {NV}
+\cs_new_protected_nopar:Npn \spath_adjust_gclose:N #1
+{
+  \spath_adjust_gclose:NV #1#1
+}
+\cs_generate_variant:Nn \spath_adjust_gclose:N {c}
 \cs_new_protected_nopar:Npn \__spath_open:n #1
 {
   \group_begin:
-  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \spath_replace_rectangles:Nn \l__spath_tmpa_tl {#1}
   \tl_clear:N \l__spath_tmpb_tl
   \bool_until_do:nn {
     \tl_if_empty_p:N \l__spath_tmpa_tl
@@ -1574,6 +2524,7 @@
   \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
   \group_end:
 }
+\cs_generate_variant:Nn \__spath_open:n {V}
 \cs_new_protected_nopar:Npn \spath_open:Nn #1#2
 {
   \__spath_open:n {#2}
@@ -1596,6 +2547,8 @@
 {
   \spath_gopen:NV #1#1
 }
+\cs_generate_variant:Nn \spath_open:N {c}
+\cs_generate_variant:Nn \spath_gopen:N {c}
 \cs_new_protected_nopar:Npn \__spath_replace_lines:n #1
 {
   \group_begin:
@@ -1707,6 +2660,115 @@
   \spath_greplace_lines:NV #1#1
 }
 \cs_generate_variant:Nn \spath_greplace_lines:N {c}
+\cs_new_protected_nopar:Npn \__spath_replace_rectangles:n #1
+{
+  \group_begin:
+  \tl_set:Nn \l__spath_tmpa_tl {#1}
+  \tl_clear:N \l__spath_tmpb_tl
+
+  \bool_do_until:nn
+  {
+    \tl_if_empty_p:N \l__spath_tmpa_tl
+  }
+  {
+    \tl_set:Nx \l__spath_tmpc_tl {\tl_head:N \l__spath_tmpa_tl }
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+    \tl_set:Nx \l__spath_tmpd_tl {\tl_head:N \l__spath_tmpa_tl }
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+    \tl_set:Nx \l__spath_tmpe_tl {\tl_head:N \l__spath_tmpa_tl }
+    \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+
+    \tl_if_eq:NNTF \l__spath_tmpc_tl \c_spath_rectcorner_tl
+    {
+
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+      \dim_set:Nn \l__spath_tmpa_dim
+      {
+        \tl_item:Nn \l__spath_tmpa_tl {1}
+      }
+      \dim_set:Nn \l__spath_tmpb_dim
+      {
+        \tl_item:Nn \l__spath_tmpa_tl {2}
+      }
+
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+      \tl_set:Nx \l__spath_tmpa_tl {\tl_tail:N \l__spath_tmpa_tl }
+
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_moveto_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 \c_spath_lineto_tl
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l__spath_tmpd_tl + \l__spath_tmpa_dim }
+        }
+      }
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpe_tl
+
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_lineto_tl
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l__spath_tmpd_tl + \l__spath_tmpa_dim }
+        }
+      }
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l__spath_tmpe_tl + \l__spath_tmpb_dim }
+        }
+      }
+
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_lineto_tl
+      \__spath_tl_put_right_braced:NV \l__spath_tmpb_tl \l__spath_tmpd_tl
+      \tl_put_right:Nx \l__spath_tmpb_tl
+      {
+        {
+          \fp_to_dim:n { \l__spath_tmpe_tl + \l__spath_tmpb_dim }
+        }
+      }
+
+      \tl_put_right:NV \l__spath_tmpb_tl \c_spath_closepath_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
+    }
+  }
+  \tl_gset_eq:NN \g__spath_output_tl \l__spath_tmpb_tl
+  \group_end:
+}
+\cs_generate_variant:Nn \__spath_replace_rectangles:n {V}
+\cs_new_protected_nopar:Npn \spath_replace_rectangles:Nn #1#2
+{
+  \__spath_replace_rectangles:n {#2}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_replace_rectangles:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_replace_rectangles:N #1
+{
+  \spath_replace_rectangles:NV #1#1
+}
+\cs_generate_variant:Nn \spath_replace_rectangles:N {c}
+\cs_new_protected_nopar:Npn \spath_greplace_rectangles:Nn #1#2
+{
+  \__spath_replace_rectangles:n {#2}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_greplace_rectangles:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_greplace_rectangles:N #1
+{
+  \spath_greplace_rectangles:NV #1#1
+}
+\cs_generate_variant:Nn \spath_greplace_rectangles:N {c}
 \cs_new_protected_nopar:Npn \__spath_remove_empty_components:n #1
 {
   \group_begin:
@@ -2000,9 +3062,11 @@
   }
   {
     \fp_set:Nn \l__spath_tmpa_fp {.5 * \l__spath_tmpa_fp / \l__spath_tmpb_fp}
-    \fp_compare:nTF
+    \bool_if:nTF
     {
-      0 < \l__spath_tmpa_fp && \l__spath_tmpa_fp < 1
+      \fp_compare_p:n {0 < \l__spath_tmpa_fp}
+      &&
+      \fp_compare_p:n {\l__spath_tmpa_fp < 1}
     }
     {
       \__spath_split_curve:nV {#1} \l__spath_tmpa_fp
@@ -2199,6 +3263,30 @@
   \tl_gclear:N \g__spath_output_tl
 }
 \cs_generate_variant:Nn \spath_gsplit_line:NNnn {NNnV, NNVn, NNVV}
+\cs_new_protected_nopar:Npn \__spath_split_rectangle:nn #1#2
+{
+  \group_begin:
+  \spath_open:Nn \l__spath_tmpa_tl {#1}
+  \fp_set:Nn \l__spath_tmpa_fp {4*(#2)}
+  \spath_split_at:NNVV
+  \l__spath_tmpa_tl \l__spath_tmpb_tl \l__spath_tmpa_tl \l__spath_tmpa_fp
+  \__spath_append_no_move:VV \l__spath_tmpb_tl \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \spath_split_rectangle:Nnn #1#2#3
+{
+  \__spath_split_rectangle:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_rectangle:Nnn {NnV, NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gsplit_rectangle:Nnn #1#2#3
+{
+  \__spath_split_rectangle:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g__spath_output_tl
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_rectangle:Nnn {NnV, NVn, NVV}
 \cs_new_protected_nopar:Npn \__spath_split_at:nn #1#2
 {
   \group_begin:
@@ -2228,11 +3316,28 @@
   \bool_set_true:N \l__spath_tmpa_bool
 
   \tl_set:Nn \l__spath_tmpe_tl {#1}
-  \tl_clear:N \l__spath_tmpc_tl
 
   \dim_zero:N \l__spath_tmpa_dim
   \dim_zero:N \l__spath_tmpb_dim
 
+  % Remember if the component is closed
+  \spath_finalaction:NV \l__spath_tmpa_tl \l__spath_tmpe_tl
+
+  \bool_set:Nn \l__spath_closed_bool
+  {
+    \tl_if_eq_p:NN \l__spath_tmpa_tl \c_spath_closepath_tl
+    ||
+    \tl_if_eq_p:NN \l__spath_tmpa_tl \c_spath_rectcorner_tl
+  }
+
+  % Open it
+  \spath_open:N \l__spath_tmpe_tl
+
+  \tl_clear:N \l__spath_tmpa_tl
+  \tl_clear:N \l__spath_tmpb_tl
+  \tl_clear:N \l__spath_tmpc_tl
+  \tl_clear:N \l__spath_tmpd_tl
+
   \bool_until_do:nn {
     \tl_if_empty_p:N \l__spath_tmpe_tl
     ||
@@ -2251,6 +3356,10 @@
       {
         \int_incr:N \l__spath_tmpb_int
       }
+      \c_spath_rectcorner_tl
+      {
+        \int_incr:N \l__spath_tmpb_int
+      }
     }
     \int_compare:nT { \l__spath_tmpb_int < \l__spath_tmpa_int  }
     {
@@ -2355,14 +3464,65 @@
         \tl_put_right:NV \l__spath_tmpc_tl \l__spath_tmpa_tl
         \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpe_tl
       }
+
+      \c_spath_rectcorner_tl
+      {
+        \tl_clear:N \l__spath_tmpd_tl
+        \tl_put_right:NV \l__spath_tmpd_tl \l__spath_tmpf_tl
+
+        \tl_put_right:Nx \l__spath_tmpd_tl {{\tl_head:N \l__spath_tmpe_tl}}
+        \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpe_tl}
+        \tl_put_right:Nx \l__spath_tmpd_tl {{\tl_head:N \l__spath_tmpe_tl}}
+        \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpe_tl}
+
+        \tl_put_right:Nx \l__spath_tmpd_tl {\tl_head:N \l__spath_tmpe_tl}
+        \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpe_tl}
+
+        \tl_put_right:Nx \l__spath_tmpd_tl {{\tl_head:N \l__spath_tmpe_tl}}
+        \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpe_tl}
+        \tl_put_right:Nx \l__spath_tmpd_tl {{\tl_head:N \l__spath_tmpe_tl}}
+        \tl_set:Nx \l__spath_tmpe_tl {\tl_tail:N \l__spath_tmpe_tl}
+
+        \spath_split_rectangle:NVV
+        \l__spath_tmpa_tl
+        \l__spath_tmpd_tl
+        \l__spath_tmpa_fp
+
+        \tl_put_right:NV \l__spath_tmpc_tl \l__spath_tmpa_tl
+        \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpe_tl
+      }
+
     }
   }
 
+  \bool_if:NT \l__spath_closed_bool
+  {
+    \prg_replicate:nn {3}
+    {
+      \tl_set:Nx \l__spath_tmpc_tl {\tl_tail:N \l__spath_tmpc_tl}
+    }
+    \tl_put_right:NV \l__spath_tmpb_tl \l__spath_tmpc_tl
+    \tl_set_eq:NN \l__spath_tmpc_tl \l__spath_tmpb_tl
+    \tl_clear:N \l__spath_tmpb_tl
+  }
+
   \tl_gclear:N \g__spath_output_tl
   \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpc_tl
   \__spath_tl_gput_right_braced:NV \g__spath_output_tl \l__spath_tmpb_tl
   \group_end:
 }
+\cs_generate_variant:Nn  \__spath_split_at:nn {nV, VV}
+\cs_new_protected_nopar:Npn \__spath_split_at_normalised:nn #1#2
+{
+  \group_begin:
+  \spath_reallength:Nn \l__spath_tmpa_int {#1}
+
+  \tl_set:Nx \l__spath_tmpa_tl
+  {\fp_to_decimal:n {(#2) * (\l__spath_tmpa_int)}}
+  \__spath_split_at:nV {#1} \l__spath_tmpa_tl
+  \group_end:
+}
+\cs_generate_variant:Nn  \__spath_split_at_normalised:nn {nV}
 \cs_new_protected_nopar:Npn \spath_split_at:NNnn #1#2#3#4
 {
   \__spath_split_at:nn {#3}{#4}
@@ -2379,6 +3539,114 @@
   \tl_gclear:N \g__spath_output_tl
 }
 \cs_generate_variant:Nn \spath_gsplit_at:NNnn {NNVn, NNVV, NNnV}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_start:Nnn #1#2#3
+{
+  \__spath_split_at:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_start:Nn #1#2
+{
+  \spath_split_at_keep_start:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_start:Nnn #1#2#3
+{
+  \__spath_split_at:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_start:Nn #1#2
+{
+  \spath_gsplit_at_keep_start:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_end:Nnn #1#2#3
+{
+  \__spath_split_at:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_keep_end:Nn #1#2
+{
+  \spath_split_at_keep_end:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_end:Nnn #1#2#3
+{
+  \__spath_split_at:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_keep_end:Nn #1#2
+{
+  \spath_gsplit_at_keep_end:NVn #1#1{#2}
+}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:NNnn #1#2#3#4
+{
+  \__spath_split_at_normalised:nn {#3}{#4}
+  \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_set:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:NNnn {NNVn, NNVV, NNnV, ccvn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:NNnn #1#2#3#4
+{
+  \__spath_split_at_normalised:nn {#3}{#4}
+  \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_gset:Nx #2 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:NNnn {NNVn, NNVV, NNnV, ccvn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_start:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_start:Nn #1#2
+{
+  \spath_split_at_normalised_keep_start:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_start:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_start:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {1}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_start:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_start:Nn #1#2
+{
+  \spath_gsplit_at_normalised_keep_start:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_start:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_end:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised_keep_end:Nn #1#2
+{
+  \spath_split_at_normalised_keep_end:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised_keep_end:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_end:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1 {\tl_item:Nn \g__spath_output_tl {2}}
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_end:Nnn {NVn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised_keep_end:Nn #1#2
+{
+  \spath_gsplit_at_normalised_keep_end:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised_keep_end:Nn {cn}
 \cs_new_protected_nopar:Npn \spath_split_at:Nnn #1#2#3
 {
   \__spath_split_at:nn {#2}{#3}
@@ -2409,6 +3677,38 @@
 {
   \spath_gsplit_at:NVn #1#1{#2}
 }
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_set:Nx #1
+  {
+    \tl_item:Nn \g__spath_output_tl {1}
+    \tl_item:Nn \g__spath_output_tl {2}
+  }
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_split_at_normalised:Nn #1#2
+{
+  \spath_split_at_normalised:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_split_at_normalised:Nn {cn}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:Nnn #1#2#3
+{
+  \__spath_split_at_normalised:nn {#2}{#3}
+  \tl_gset:Nx #1
+  {
+    \tl_item:Nn \g__spath_output_tl {1}
+    \tl_item:Nn \g__spath_output_tl {2}
+  }
+  \tl_gclear:N \g__spath_output_tl
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:Nnn {NVn, NVV}
+\cs_new_protected_nopar:Npn \spath_gsplit_at_normalised:Nn #1#2
+{
+  \spath_gsplit_at_normalised:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \spath_gsplit_at_normalised:Nn {cn}
 \cs_new_protected_nopar:Npn \__spath_shorten_at_end:nn #1#2
 {
   \int_compare:nTF
@@ -2714,6 +4014,28 @@
   \spath_gshorten_at_start:NVn #1#1{#2}
 }
 \cs_generate_variant:Nn \spath_gshorten_at_start:Nn {cn, cV, NV}
+\cs_new_protected_nopar:Npn \spath_shorten_at_both_ends:Nnn #1#2#3
+{
+  \spath_shorten_at_start:Nnn #1{#2}{#3}
+  \spath_shorten_at_end:Nnn #1{#2}{#3}
+}
+\cs_new_protected_nopar:Npn \spath_shorten_at_both_ends:Nn #1#2
+{
+  \spath_shorten_at_start:Nn #1{#2}
+  \spath_shorten_at_end:Nn #1{#2}
+}
+\cs_generate_variant:Nn \spath_shorten_at_both_ends:Nn {cn, cV, NV}
+\cs_new_protected_nopar:Npn \spath_gshorten_at_both_ends:Nnn #1#2#3
+{
+  \spath_gshorten_at_start:Nnn #1{#2}{#3}
+  \spath_gshorten_at_end:Nnn #1{#2}{#3}
+}
+\cs_new_protected_nopar:Npn \spath_gshorten_at_both_ends:Nn #1#2
+{
+  \spath_gshorten_at_start:Nn #1{#2}
+  \spath_gshorten_at_end:Nn #1{#2}
+}
+\cs_generate_variant:Nn \spath_gshorten_at_both_ends:Nn {cn, cV, NV}
 \cs_new_protected_nopar:Npn \__spath_point_at:nn #1#2
 {
   \group_begin:
@@ -2792,6 +4114,95 @@
           }
         }
 
+        \c_spath_rectsize_tl
+        {
+          \fp_compare:nTF
+          {
+            \l__spath_tmpa_fp <= .25
+          }
+          {
+            \tl_set:Nx \l__spath_tmpc_tl
+            {
+              {\fp_to_dim:n
+                {
+                  ( \tl_item:Nn \l__spath_tmpa_tl {2} )
+                  +
+                  4 * \l__spath_tmpa_fp * ( \tl_item:Nn \l__spath_tmpa_tl {5} )
+                }
+              }
+              {\fp_to_dim:n {\tl_item:Nn \l__spath_tmpa_tl {3} } }
+            }
+          }
+          {
+            \fp_compare:nTF
+            {
+              \l__spath_tmpa_fp <= .5
+            }
+            {
+              \tl_set:Nx \l__spath_tmpc_tl
+              {
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l__spath_tmpa_tl {2} )
+                    +
+                    ( \tl_item:Nn \l__spath_tmpa_tl {5} )
+                  }
+                }
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l__spath_tmpa_tl {3} )
+                    +
+                    (4 * (\l__spath_tmpa_fp) - 1) * ( \tl_item:Nn \l__spath_tmpa_tl {6} )
+                  }
+                }
+              }
+            }
+            {
+              \fp_compare:nTF
+              {
+                \l__spath_tmpa_fp <= .75
+              }
+              {
+                \tl_set:Nx \l__spath_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l__spath_tmpa_tl {2} )
+                      +
+                      (3 - 4 * (\l__spath_tmpa_fp)) *( \tl_item:Nn \l__spath_tmpa_tl {5} )
+                    }
+                  }
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l__spath_tmpa_tl {3} )
+                      +
+                      ( \tl_item:Nn \l__spath_tmpa_tl {6} )
+                    }
+                  }
+                }
+
+              }
+              {
+                \tl_set:Nx \l__spath_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l__spath_tmpa_tl {2} )
+                    }
+                  }
+                  {\fp_to_dim:n
+                    {
+                      ( \tl_item:Nn \l__spath_tmpa_tl {3} )
+                      +
+                      (4 - 4 *(\l__spath_tmpa_fp)) * ( \tl_item:Nn \l__spath_tmpa_tl {6} )
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
         \c_spath_closepath_tl
         {
           \tl_set:Nx \l__spath_tmpc_tl
@@ -2937,6 +4348,71 @@
           }
         }
 
+        \c_spath_rectsize_tl
+        {
+          \fp_compare:nTF
+          {
+            \l__spath_tmpa_fp <= .25
+          }
+          {
+            \tl_set:Nx \l__spath_tmpc_tl
+            {
+              {\fp_to_dim:n
+                {
+                  \tl_item:Nn \l__spath_tmpa_tl {5}
+                }
+              }
+              {0pt}
+            }
+          }
+          {
+            \fp_compare:nTF
+            {
+              \l__spath_tmpa_fp <= .5
+            }
+            {
+              \tl_set:Nx \l__spath_tmpc_tl
+              {
+                {0pt}
+                {\fp_to_dim:n
+                  {
+                    ( \tl_item:Nn \l__spath_tmpa_tl {6} )
+                  }
+                }
+              }
+            }
+            {
+              \fp_compare:nTF
+              {
+                \l__spath_tmpa_fp <= .75
+              }
+              {
+                \tl_set:Nx \l__spath_tmpc_tl
+                {
+                  {\fp_to_dim:n
+                    {
+                      -( \tl_item:Nn \l__spath_tmpa_tl {5} )
+                    }
+                  }
+                  {0pt}
+                }
+
+              }
+              {
+                \tl_set:Nx \l__spath_tmpc_tl
+                {
+                  {0pt}
+                  {\fp_to_dim:n
+                    {
+                      - ( \tl_item:Nn \l__spath_tmpa_tl {6} )
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+
         \c_spath_closepath_tl
         {
           \tl_set:Nx \l__spath_tmpc_tl
@@ -3083,8 +4559,6 @@
   \tl_set:Nn \l__spath_tmpb_tl {#1}
   \tl_set:Nn \l__spath_tmpc_tl {#2}
 
-  \spath_reallength:Nn \l__spath_tmpa_int {#1}
-
   % Remember if the component is closed
   \spath_finalaction:NV \l__spath_tmpa_tl \l__spath_tmpb_tl
 
@@ -3091,11 +4565,15 @@
   \bool_set:Nn \l__spath_closed_bool
   {
     \tl_if_eq_p:NN \l__spath_tmpa_tl \c_spath_closepath_tl
+    ||
+    \tl_if_eq_p:NN \l__spath_tmpa_tl \c_spath_rectcorner_tl
   }
 
   % Open it
   \spath_open:N \l__spath_tmpb_tl
 
+  \spath_reallength:NV \l__spath_tmpa_int \l__spath_tmpb_tl
+
   % Sort intersections along the component
   \pgfintersectionsortbyfirstpath
   \spath_intersect:NN \l__spath_tmpb_tl \l__spath_tmpc_tl
@@ -3118,6 +4596,7 @@
     {
       \bool_set_false:N \l__spath_closed_bool
     }
+
     \seq_get_right:NN \l__spath_tmpb_seq \l__spath_tmpa_tl
     \fp_compare:nT
     {
@@ -3925,11 +5404,13 @@
 {
   \pgfsyssoftpath at getcurrentpath #1
 }
+\cs_generate_variant:Nn \spath_get_current_path:N {c}
 \cs_new_protected_nopar:Npn \spath_gget_current_path:N #1
 {
   \pgfsyssoftpath at getcurrentpath #1
   \tl_gset_eq:NN #1 #1
 }
+\cs_generate_variant:Nn \spath_gget_current_path:N {c}
 \cs_new_protected_nopar:Npn \spath_protocol_path:n #1
 {
   \spath_minbb:Nn \l__spath_tmpa_tl {#1}
@@ -3958,10 +5439,13 @@
 }
 \cs_new_protected_nopar:Npn \spath_tikz_path:nn #1#2
 {
-  \path[#1] \pgfextra{
-    \spath_set_current_path:n {#2}
-    \tl_put_right:Nn \tikz at preactions {\def\tikz at actions@path{#2}}
-  };
+  \tl_if_empty:nF {#2}
+  {
+    \path[#1] \pgfextra{
+      \spath_set_current_path:n {#2}
+      \tl_put_left:Nn \tikz at preactions {\def\tikz at actions@path{#2}}
+    };
+  }
 }
 \cs_generate_variant:Nn \spath_tikz_path:nn {Vn, VV, nv, Vv, nV}
 \cs_new_protected_nopar:Npn \spath_set_tikz_data:n #1
@@ -3969,8 +5453,8 @@
   \spath_finalpoint:Nn \l__spath_tmpa_tl {#1}
   \tl_set:Nx \l__spath_tmpa_tl
   {
-    \exp_not:c {pgf at x}=\tl_item:Nn \l__spath_tmpa_tl {1}
-    \exp_not:c {pgf at y}=\tl_item:Nn \l__spath_tmpa_tl {2}
+    \exp_not:c {pgf at x}=\tl_item:Nn \l__spath_tmpa_tl {1} \relax
+    \exp_not:c {pgf at y}=\tl_item:Nn \l__spath_tmpa_tl {2} \relax
   }
   \use:c {pgf at process}{%
     \tl_use:N \l__spath_tmpa_tl
@@ -3979,20 +5463,23 @@
   }
   \tl_set:Nx \l__spath_tmpa_tl
   {
-    \exp_not:c {tikz at lastx}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lasty}=\exp_not:c {pgf at y}
-    \exp_not:c {tikz at lastxsaved}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lastysaved}=\exp_not:c {pgf at y}
+    \exp_not:c {tikz at lastx}=\exp_not:c {pgf at x} \relax
+    \exp_not:c {tikz at lasty}=\exp_not:c {pgf at y} \relax
+    \exp_not:c {tikz at lastxsaved}=\exp_not:c {pgf at x} \relax
+    \exp_not:c {tikz at lastysaved}=\exp_not:c {pgf at y} \relax
   }
   \tl_use:N \l__spath_tmpa_tl
   \spath_finalmovepoint:Nn \l__spath_tmpa_tl {#1}
-  \ifpgfsyssoftpathmovetorelevant%
-  \tl_gset_eq:cN {pgfsyssoftpath at lastmoveto} \l__spath_tmpa_tl
-  \fi
+  \bool_if:NT \l_spath_movetorelevant_bool
+  {
+    \ifpgfsyssoftpathmovetorelevant%
+    \tl_gset_eq:cN {pgfsyssoftpath at lastmoveto} \l__spath_tmpa_tl
+    \fi
+  }
   \tl_set:Nx \l__spath_tmpa_tl
   {
-    \exp_not:c {pgf at x}=\tl_item:Nn \l__spath_tmpa_tl {1}
-    \exp_not:c {pgf at y}=\tl_item:Nn \l__spath_tmpa_tl {2}
+    \exp_not:c {pgf at x}=\tl_item:Nn \l__spath_tmpa_tl {1} \relax
+    \exp_not:c {pgf at y}=\tl_item:Nn \l__spath_tmpa_tl {2} \relax
   }
   \use:c {pgf at process}{%
     \tl_use:N \l__spath_tmpa_tl
@@ -3999,12 +5486,18 @@
     \pgftransforminvert
     \use:c {pgf at pos@transform at glob}
   }
-  \tl_set:Nx \l__spath_tmpa_tl
+  \bool_if:NT \l_spath_movetorelevant_bool
   {
-    \exp_not:c {tikz at lastmovetox}=\exp_not:c {pgf at x}
-    \exp_not:c {tikz at lastmovetoy}=\exp_not:c {pgf at y}
+    \dim_if_exist:cT {tikz at lastmovetox}
+    {
+      \tl_set:Nx \l__spath_tmpa_tl
+      {
+        \exp_not:c {tikz at lastmovetox}=\exp_not:c {pgf at x} \relax
+        \exp_not:c {tikz at lastmovetoy}=\exp_not:c {pgf at y} \relax
+      }
+      \tl_use:N \l__spath_tmpa_tl
+    }
   }
-  \tl_use:N \l__spath_tmpa_tl
   \tl_clear_new:c {tikz at timer}
   \tl_set:cn {tikz at timer}
   {

Modified: trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryknots.code.tex	2022-10-26 19:59:14 UTC (rev 64818)
@@ -59,6 +59,7 @@
 \bool_new:N \l__knot_append_next_bool
 \bool_new:N \l__knot_skip_bool
 \bool_new:N \l__knot_save_bool
+\bool_new:N \l__knot_debugging_bool
 
 \seq_new:N \g__knot_nodes_seq
 
@@ -191,6 +192,14 @@
     \bool_set_true:N \l__knot_draft_bool
     \bool_set_true:N \l__knot_super_draft_bool
   },
+  debug/.is~ choice,
+  debug/true/.code={
+    \bool_set_true:N \l__knot_debugging_bool
+  },
+  debug/false/.code={
+    \bool_set_false:N \l__knot_debugging_bool
+  },
+  debug/.default=true,
   draft/.is~ family,
   draft,
   crossing~ label/.style={
@@ -212,8 +221,18 @@
     inner~ sep=0pt
   },
 }
+\cs_new_nopar:Npn \knot_debug:n #1
+{
+  \bool_if:NT \l__knot_debugging_bool
+  {
+    \iow_term:n {===Knot~ debug: #1===}
+  }
+}
+
+\cs_generate_variant:Nn \knot_debug:n {x}
 \cs_new_nopar:Npn \knot_apply_style:N #1
 {
+  \knot_debug:n {knot~ apply~ style}
   \tl_if_exist:NT #1 {
     \exp_args:NV \tikzset #1
   }
@@ -239,6 +258,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_initialise:n #1
 {
+  \knot_debug:n {knot~ initialise}
   \tikzset{knot~ diagram/.cd,every~ knot~ diagram/.try,#1}
   \int_zero:N \l__knot_strands_int
   \tl_clear:N \l__knot_redraws_tl
@@ -246,6 +266,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_render:
 {
+  \knot_debug:n {knot~ render}
   \pgfscope
   \pgftransformreset
   \dim_set:Nn \l__knot_redraw_tolerance_dim {\fp_to_dim:n
@@ -296,9 +317,12 @@
     \seq_use:Nn \g__knot_nodes_seq {}
   }
   \endpgfscope
+  \knot_debug:x {knot~rendered,
+    ~found~\int_use:N  \g__knot_intersections_int \c_space_tl~intersections}
 }
 \cs_new_protected_nopar:Npn \knot_draw_strand:n #1
 {
+  \knot_debug:n {knot~ draw~ strand~ #1}
   \pgfscope
   \group_begin:
   \spath_bake_round:c {knot strand #1}
@@ -308,7 +332,7 @@
   {
     ,
     knot~ diagram/only~ when~ rendering/.try,
-    only~ when~ rendering/.try
+    only~ when~ rendering/.try,
   }
   \spath_tikz_path:Vv \l__knot_tmpa_tl {knot strand #1}
   \group_end:
@@ -317,6 +341,7 @@
 \cs_generate_variant:Nn \tl_put_right:Nn {Nv}
 \cs_new_protected_nopar:Npn \knot_draw_labels:n #1
 {
+  \knot_debug:n {knot~ draw~ labels}
   \bool_if:NT \l__knot_draft_bool
   {
     \spath_finalpoint:Nv \l__knot_tmpb_tl {knot strand #1}
@@ -348,6 +373,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_split_self_intersects:N #1
 {
+  \knot_debug:n {knot~ split~ self~ intersects}
   \tl_set:Nx \l__knot_tmpc_tl {\tl_item:nn {#1} {4}}
   \tl_case:NnF \l__knot_tmpc_tl
   {
@@ -385,9 +411,11 @@
       }
       {
         \fp_set:Nn \l__knot_tmpa_fp {.5 * \l__knot_tmpa_fp / \l__knot_tmpb_fp}
-        \fp_compare:nTF
+        \bool_if:nTF
         {
-          0 < \l__knot_tmpa_fp && \l__knot_tmpa_fp < 1
+          \fp_compare_p:n {0 < \l__knot_tmpa_fp}
+          &&
+          \fp_compare_p:n {\l__knot_tmpa_fp < 1}
         }
         {
           \spath_split_curve:NNnV
@@ -435,6 +463,8 @@
 }
 \cs_new_protected_nopar:Npn \knot_intersections:nn #1#2
 {
+  \knot_debug:x {knot~ intersections~ between~
+    \l__knot_prefix_tl \c_space_tl #1~ and~ #2}
   \group_begin:
   \tl_set_eq:NN \l__knot_tmpa_tl \l__knot_prefix_tl
   \tl_put_right:Nn \l__knot_tmpa_tl {#1}
@@ -466,6 +496,7 @@
 
   }
 
+  \knot_debug:x {found~\pgfintersectionsolutions\c_space_tl~ intersections}
   \int_compare:nT {\pgfintersectionsolutions > 0}
   {
     \int_step_function:nnnN
@@ -480,6 +511,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_save_intersections:nn #1#2
 {
+  \knot_debug:n {knot~ save~ intersections}
   \bool_if:NT \l__knot_save_bool
   {
     \tl_clear:N \l__knot_aux_tl
@@ -527,9 +559,12 @@
 \cs_generate_variant:Nn \knot_save_intersections:nn {VV}
 \cs_new_protected_nopar:Npn \knot_do_intersection:n #1
 {
+  \knot_debug:n {knot~ do~ intersection~ #1}
   \pgfpointintersectionsolution{#1}
   \dim_set:Nn \l__knot_tmpa_dim {\pgf at x}
   \dim_set:Nn \l__knot_tmpb_dim {\pgf at y}
+  \knot_debug:x {intersection~at~
+    (\dim_use:N \l__knot_tmpa_dim,\dim_use:N \l__knot_tmpb_dim)}
   \bool_set_false:N \l__knot_skip_bool
   \bool_if:NT \l__knot_self_intersections_bool
   {
@@ -578,6 +613,7 @@
   {
 
     \int_gincr:N \g__knot_intersections_int
+    \knot_debug:x {Processing~intersection~\int_use:N \g__knot_intersections_int}
     \bool_if:nF
     {
       \tl_if_exist_p:c {l__knot_ignore_crossing_ \int_use:N
@@ -643,6 +679,8 @@
             !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl}
           }
           {
+            \knot_debug:x {Prepending~
+              \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}}
             \spath_prepend_no_move:cv
             {knot \tl_use:N \l__knot_prefix_tl -1}
             {knot \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}}
@@ -650,9 +688,13 @@
             {
               \l__knot_splits_bool
               &&
-              \tl_if_exist_p:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+              \tl_if_exist_p:c {knot previous
+                \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+              }
               &&
-              !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+              !\tl_if_empty_p:c {knot previous
+                \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+              }
             }
             {
               \knot_test_endpoint:NvnT
@@ -660,6 +702,11 @@
               {knot previous \tl_use:N \l__knot_tmpg_tl}
               {initial point}
               {
+                \knot_debug:x {Prepending~
+                  \tl_use:c {knot previous
+                    \tl_use:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+                  }
+                }
                 \spath_prepend_no_move:cv
                 {knot \tl_use:N \l__knot_prefix_tl -1}
                 {knot \tl_use:c
@@ -667,10 +714,12 @@
                     {knot previous \tl_use:N \l__knot_tmpg_tl}
                   }
                 }
-                \tl_set_eq:Nc \l__knot_tmpa_tl {knot \tl_use:N \l__knot_prefix_tl -1}
+                \tl_set_eq:Nc \l__knot_tmpa_tl
+                {knot \tl_use:N \l__knot_prefix_tl -1}
               }
             }
           }
+
           \bool_if:nT
           {
             \l__knot_append_next_bool
@@ -677,9 +726,11 @@
             &&
             \tl_if_exist_p:c {knot next \tl_use:N \l__knot_tmpg_tl}
             &&
-            !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+            !\tl_if_empty_p:c {knot next \tl_use:N \l__knot_tmpg_tl}
           }
           {
+            \knot_debug:x {Appending~
+              \tl_use:c {knot next \tl_use:N \l__knot_tmpg_tl}}
             \spath_append_no_move:cv
             {knot \tl_use:N \l__knot_prefix_tl -1}
             {knot \tl_use:c {knot next \tl_use:N \l__knot_tmpg_tl}}
@@ -687,17 +738,25 @@
             {
               \l__knot_splits_bool
               &&
-              \tl_if_exist_p:c {knot previous \tl_use:N
-                \l__knot_tmpg_tl}
+              \tl_if_exist_p:c {knot next \tl_use:c { knot next \tl_use:N
+                \l__knot_tmpg_tl}}
               &&
-              !\tl_if_empty_p:c {knot previous \tl_use:N \l__knot_tmpg_tl}
+              !\tl_if_empty_p:c {knot next
+                \tl_use:c { knot next \tl_use:N \l__knot_tmpg_tl}
+              }
             }
             {
+              \knot_debug:x {Testing~ whether~ to~ append~
+                {knot next \tl_use:c { knot next \tl_use:N \l__knot_tmpg_tl}}
+              }
               \knot_test_endpoint:NvnT
               \l__knot_redraw_tolerance_dim
-              {knot previous \tl_use:N \l__knot_tmpg_tl}
+              {knot next \tl_use:N \l__knot_tmpg_tl}
               {final point}
               {
+                \knot_debug:x {Appending~
+                  {knot next \tl_use:c { knot next \tl_use:N \l__knot_tmpg_tl}}
+                }
                 \spath_append_no_move:cv
                 {knot \tl_use:N \l__knot_prefix_tl -1}
                 {knot \tl_use:c
@@ -773,6 +832,7 @@
 \cs_generate_variant:Nn \knot_test_endpoint:NnnTF {NVnTF,NvnTF}
 \cs_new_protected_nopar:Npn \knot_draw_crossing:nnn #1#2#3
 {
+  \knot_debug:n {knot~ draw~ crossing}
   \group_begin:
   \pgfscope
   \path[knot~ diagram/background~ clip] (#2, #3)
@@ -821,6 +881,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_split_strands:
 {
+  \knot_debug:n {knot~ split~ strands}
   \int_gzero:N \g__knot_filaments_int
   \int_step_function:nnnN {1} {1} {\l__knot_strands_int} \knot_split_strand:n
   \int_step_function:nnnN {1} {1} {\g__knot_filaments_int} \knot_compute_nexts:n
@@ -827,11 +888,13 @@
 }
 \cs_new_protected_nopar:Npn \knot_compute_nexts:n #1
 {
+  \knot_debug:n {knot~ compute~ nexts}
   \tl_clear_new:c {knot next \tl_use:c {knot previous filament #1}}
   \tl_set:cn {knot next \tl_use:c {knot previous filament #1}} {filament #1}
 }
 \cs_new_protected_nopar:Npn \knot_split_strand:n #1
 {
+  \knot_debug:n {knot~ split~ strand}
   \int_set_eq:NN \l__knot_component_start_int \g__knot_filaments_int
   \int_incr:N \l__knot_component_start_int
   \tl_set_eq:Nc \l__knot_tmpa_tl {l__knot_options_strand #1}
@@ -840,6 +903,7 @@
 }
 \cs_new_protected_nopar:Npn \knot_save_filament:N #1
 {
+  \knot_debug:n {knot~ save~ filament}
   \tl_set:Nx \l__knot_tmpb_tl {\tl_item:nn {#1} {4}}
   \tl_case:NnF \l__knot_tmpb_tl
   {

Modified: trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/texmf-dist/tex/latex/spath3/tikzlibraryspath3.code.tex	2022-10-26 19:59:14 UTC (rev 64818)
@@ -16,33 +16,79 @@
 \RequirePackage{expl3}
 \ExplSyntaxOn
 
-\tl_new:N \l__spath_current_tl
-\tl_new:N \l__spath_reverse_tl
-\tl_new:N \l__spath_prefix_tl
-\tl_new:N \l__spath_suffix_tl
-\tl_new:N \g__spath_smuggle_tl
-\seq_new:N \g__spath_tmpa_seq
-\seq_new:N \g__spath_tmpb_seq
-\bool_new:N \l__spath_draft_bool
-\msg_new:nnn { spath3 } { missing soft path } { Soft~ path~ #1~ doesn't~ exist }
-\msg_new:nnnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty}
+\tl_new:N \l__tikzspath_tmpa_tl
+\tl_new:N \l__tikzspath_tmpb_tl
+\tl_new:N \l__tikzspath_tmpc_tl
+\tl_new:N \l__tikzspath_tmpd_tl
+\tl_new:N \l__tikzspath_tmpe_tl
+\tl_new:N \l__tikzspath_tmpf_tl
+
+\int_new:N \l__tikzspath_tmpa_int
+\seq_new:N \l__tikzspath_tmpa_seq
+\seq_new:N \l__tikzspath_tmpb_seq
+\seq_new:N \l__tikzspath_tmpc_seq
+\seq_new:N \l__tikzspath_tmpd_seq
+
+\tl_new:N \l__tikzspath_current_tl
+\tl_new:N \l__tikzspath_reverse_tl
+\tl_new:N \l__tikzspath_prefix_tl
+\tl_new:N \l__tikzspath_suffix_tl
+\tl_new:N \g__tikzspath_smuggle_tl
+\tl_new:N \g__tikzspath_output_tl
+\tl_new:N \l__tikzspath_check_tl
+\clist_new:N \g__tikzspath_output_clist
+\seq_new:N \g__tikzspath_tmpa_seq
+\seq_new:N \g__tikzspath_tmpb_seq
+\seq_new:N \g__tikzspath_output_seq
+\bool_new:N \l__tikzspath_draft_bool
+\msg_new:nnn { spath3 } { missing soft path }
+{ Soft~ path~ #1~ doesn't~ exist~ \msg_line_context:}
+\msg_new:nnnn { spath3 } { empty soft path }
+{ Soft~ path~ #1~ is~ empty~ \msg_line_context:}
 {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
+{ You~ need~ to~ load~ the~ "intersections"~ library~
+  to~ work~ with~ intersections }
+\tl_set:Nn \l__tikzspath_prefix_tl {tikz at intersect@path at name@}
+\tl_set:Nn \l__tikzspath_suffix_tl {}
+\tl_new:N \g__tikzspath_tikzfinish_tl
+\tl_new:N \l__tikzspath_tikzfinish_outside_tl
 \cs_new_protected_nopar:Npn \spath_at_end_of_path:
 {
-  \tl_use:N \g__spath_tikzfinish_tl
-  \tl_gclear:N \g__spath_tikzfinish_tl
+  \tl_use:N \g__tikzspath_tikzfinish_tl
+  \tl_gclear:N \g__tikzspath_tikzfinish_tl
 }
 \tl_put_right:Nn \tikz at finish {\spath_at_end_of_path:}
 
+\tikzset{
+  every~ scope/.append~ style={
+    execute~ at~ begin~ scope={
+      \tl_set_eq:NN \l__tikzspath_tikzfinish_outside_tl \g__tikzspath_tikzfinish_tl
+    },
+    execute~ at~ end~ scope={
+      \tl_use:N \g__tikzspath_tikzfinish_tl
+      \tl_gclear:N \g__tikzspath_tikzfinish_tl
+      \tl_gset_eq:NN \g__tikzspath_tikzfinish_tl \l__tikzspath_tikzfinish_outside_tl
+    },
+  },
+}
+\tl_new:N \l__tikzspath_tikzpath_finish_tl
+
+\cs_new_protected_nopar:Npn \__tikzspath_at_end_of_path_construction:
+{
+  \tl_use:N \l__tikzspath_tikzpath_finish_tl
+  \tl_clear:N \l__tikzspath_tikzpath_finish_tl
+}
+
+\tl_put_left:Nn \tikz at finish {\__tikzspath_at_end_of_path_construction:}
 \cs_new_protected_nopar:Npn \spath_save_path:Nn #1#2
 {
-  \tl_gput_right:Nn \g__spath_tikzfinish_tl
+  \tl_if_empty:NF \g__tikzspath_tikzfinish_tl
   {
+    \tl_use:N \g__tikzspath_tikzfinish_tl
+  }
+  \tl_gput_right:Nn \g__tikzspath_tikzfinish_tl
+  {
     \tl_clear_new:N #1
     \tl_set:Nn #1 {#2}
   }
@@ -51,7 +97,7 @@
 
 \cs_new_protected_nopar:Npn \spath_gsave_path:Nn #1#2
 {
-  \tl_gput_right:Nn \g__spath_tikzfinish_tl
+  \tl_gput_right:Nn \g__tikzspath_tikzfinish_tl
   {
     \tl_gclear_new:N #1
     \tl_gset:Nn #1 {#2}
@@ -58,30 +104,208 @@
   }
 }
 \cs_generate_variant:Nn \spath_gsave_path:Nn {cn, NV, cV}
-\cs_new_protected_nopar:Npn \__spath_process_tikz_point:Nn #1#2
+\cs_new_protected_nopar:Npn \__tikzspath_process_tikz_point:Nn #1#2
 {
   \group_begin:
   \use:c {tikz at scan@one at point} \use:n #2 \scan_stop:
-  \tl_gset:Nx \g__spath_output_tl
+  \tl_gset:Nx \g__tikzspath_output_tl
   {
     { \dim_use:c {pgf at x} }
     { \dim_use:c {pgf at y} }
   }
   \group_end:
-  \tl_set_eq:NN #1 \g__spath_output_tl
-  \tl_gclear:N \g__spath_output_tl
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_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_set_eq:NN \__tikzspath_tikzset:n \tikzset
+\cs_generate_variant:Nn \__tikzspath_tikzset:n {V, v}
+\cs_new_protected_nopar:Npn \__tikzspath_check_path:nnn #1#2#3
+{
+  \tl_set:Nn \l__tikzspath_check_tl {#3}
+  \tl_if_exist:cTF {\__tikzspath_path_name:n {#2}}
+  {
+    \tl_if_empty:cTF {\__tikzspath_path_name:n {#2}}
+    {
+      \msg_warning:nnn { spath3 } { empty soft path } { #2 }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_check_tl {
+        #1 {\__tikzspath_path_name:n {#2}}
+      }
+    }
+  }
+  {
+    \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+  }
+  \tl_use:N \l__tikzspath_check_tl
+}
+\cs_new_protected_nopar:Npn \__tikzspath_check_two_paths:nnnn #1#2#3#4
+{
+  \__tikzspath_check_path:nnn {
+    \__tikzspath_check_path:nnn {#1}{#2}{#4}
+  }{#3}{#4}
+}
+\cs_new_protected_nopar:Npn \__tikzspath_check_three_paths:nnnnn #1#2#3#4#5
+{
+  \__tikzspath_check_path:nnn {
+    \__tikzspath_check_path:nnn {
+      \__tikzspath_check_path:nnn {#1}{#2}{#5}
+    }{#3}{#5}
+  }{#4}{#5}
+}
+\cs_generate_variant:Nn \__tikzspath_check_path:nnn {nVn}
+\cs_generate_variant:Nn \__tikzspath_check_two_paths:nnnn {nnVn}
+\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_path:nn #1#2
+{
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
+  }
+  #1 {#2}
+}
+\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_path_reuse:nnn #1#2#3
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
+  }
+  #1 {#2} #3
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\__tikzspath_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\__tikzspath_path_name:n {#2}}
+      \spath_set_tikz_data:v {\__tikzspath_path_name:n {#2}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_two_paths_reuse_both:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\__tikzspath_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\__tikzspath_path_name:n {#2}}
+      \spath_set_tikz_data:v {\__tikzspath_path_name:n {#2}}
+    }
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \tl_if_empty:cF {\__tikzspath_path_name:n {#3}}
+    {
+      \spath_set_current_path:c {\__tikzspath_path_name:n {#3}}
+      \spath_set_tikz_data:v {\__tikzspath_path_name:n {#3}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_two_paths_reuse_first:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \tl_if_empty:cF {\__tikzspath_path_name:n {#2}}
+    {
+      \spath_set_current_path:c {\__tikzspath_path_name:n {#2}}
+      \spath_set_tikz_data:v {\__tikzspath_path_name:n {#2}}
+    }
+  }
+}
+\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_two_paths_reuse_second:nnnn #1#2#3#4
+{
+  \bool_set_true:N \l_spath_movetorelevant_bool
+  \tl_if_eq:nnT {#2} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
+  }
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \spath_get_current_path:c {\__tikzspath_path_name:n {#3}}
+  }
+  #1 {#2} {#3} #4
+  \tl_if_eq:nnT {#3} {current}
+  {
+    \tl_if_empty:cF {\__tikzspath_path_name:n {#3}}
+    {
+      \spath_set_current_path:c {\__tikzspath_path_name:n {#3}}
+      \spath_set_tikz_data:v {\__tikzspath_path_name:n {#3}}
+    }
+  }
+}
+\cs_generate_variant:Nn \__tikzspath_maybe_current_path:nn {nV}
+\cs_generate_variant:Nn \__tikzspath_maybe_current_path_reuse:nnn {nVn}
+\cs_new_protected_nopar:Npn \__tikzspath_seq_from_foreach:Nnn #1#2#3
+{
+  \group_begin:
+  \seq_gclear:N \g__tikzspath_output_seq
 
-\cs_new_protected_nopar:Npn \__spath_set_bool:Nn #1#2
+  \tl_if_empty:nTF {#3}
+  {
+    \int_step_inline:nnnn {1}{1} {#2}
+    {
+      \seq_gput_right:Nn \g__tikzspath_output_seq {##1}
+    }
+  }
+  {
+    \foreach \l__tikzspath_tmpa_tl in {#3}
+    {
+      \int_compare:nTF { \l__tikzspath_tmpa_tl > 0 }
+      {
+        \seq_gput_right:NV \g__tikzspath_output_seq \l__tikzspath_tmpa_tl
+      }
+      {
+        \seq_gput_right:Nx \g__tikzspath_output_seq
+        {\int_eval:n {#2 - \l__tikzspath_tmpa_tl}}
+      }
+    }
+    \seq_gsort:Nn \g__tikzspath_output_seq
+    {
+      \int_compare:nNnTF {##1} < {##2}
+      { \sort_return_same: }
+      { \sort_return_swapped: }
+    }
+  }
+  \group_end:
+  \seq_set_eq:NN #1 \g__tikzspath_output_seq
+  \seq_gclear:N \g__tikzspath_output_seq
+}
+\cs_generate_variant:Nn \__tikzspath_seq_from_foreach:Nnn {NVV, NVn}
+\cs_new:Npn \__tikzspath_path_name:n #1
 {
+  \tl_use:N \l__tikzspath_prefix_tl
+  #1
+  \tl_use:N \l__tikzspath_suffix_tl
+}
+\cs_generate_variant:Nn \__tikzspath_path_name:n {V}
+\bool_new:N \l__tikzspath_reverse_bool
+\bool_new:N \l__tikzspath_weld_bool
+\bool_new:N \l__tikzspath_move_bool
+\bool_new:N \l__tikzspath_global_bool
+\bool_new:N \l__tikzspath_current_transformation_bool
+\tl_new:N \l__tikzspath_joinpath_tl
+\tl_new:N \l__tikzspath_transformation_tl
+
+\cs_new_protected_nopar:Npn \__tikzspath_set_bool:Nn #1#2
+{
   \tl_if_eq:nnTF {#2}{false}
   {
     \bool_set_false:N #1
@@ -94,231 +318,805 @@
   spath/join/.is~ family,
   spath/join/.cd,
   reverse/.code = {
-    \__spath_set_bool:Nn \l__spath_reverse_bool {#1}
+    \__tikzspath_set_bool:Nn \l__tikzspath_reverse_bool {#1}
   },
   reverse/.default = true,
   weld/.code = {
-    \__spath_set_bool:Nn \l__spath_weld_bool {#1}
+    \__tikzspath_set_bool:Nn \l__tikzspath_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}
+    \__tikzspath_set_bool:Nn \l__tikzspath_weld_bool {#1}
+    \bool_set:Nn \l__tikzspath_weld_bool {! \l__tikzspath_weld_bool}
   },
   no~ weld/.default = true,
   move/.code = {
-    \__spath_set_bool:Nn \l__spath_move_bool {#1}
+    \__tikzspath_set_bool:Nn \l__tikzspath_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}
+    \__tikzspath_set_bool:Nn \l__tikzspath_move_bool {#1}
+    \bool_set:Nn \l__tikzspath_move_bool {! \l__tikzspath_move_bool}
   },
   no~ move/.default = true,
   global/.code = {
-    \__spath_set_bool:Nn \l__spath_global_bool {#1}
+    \__tikzspath_set_bool:Nn \l__tikzspath_global_bool {#1}
   },
   global/.default = true,
-  transform/.store~in=\l__spath_transformation_tl,
+  use~ current~ transformation/.code={
+    \__tikzspath_set_bool:Nn \l__tikzspath_current_transformation_bool {#1}
+  },
+  use~ current~ transformation/.default = true,
+  transform/.store~in=\l__tikzspath_transformation_tl,
   .unknown/.code = {
-    \tl_set_eq:NN \l__spath_joinpath_tl \pgfkeyscurrentname
+    \tl_set_eq:NN \l__tikzspath_joinpath_tl \pgfkeyscurrentname
   }
 }
 \cs_set_eq:NN \getComponentOf \clist_item:Nn
-\tikzset{
-  spath/.is~family,
-  spath/.cd,
-  set~ prefix/.store~ in=\l__spath_prefix_tl,
-  prefix/.is~choice,
-  prefix/default/.style={
-    /tikz/spath/set~ prefix=tikz at intersect@path at name@
-  },
-  set~ suffix/.store~ in=\l__spath_suffix_tl,
-  suffix/.is~choice,
-  suffix/default/.style={
-    /tikz/spath/set~ suffix={}
-  },
-  set~ name/.style={
-    /tikz/spath/prefix=#1,
-    /tikz/spath/suffix=#1
-  },
-  save/.code={
-    \tikz at addmode{
-      \spath_get_current_path:N \l__spath_tmpa_tl
-      \spath_bake_round:NV \l__spath_tmpa_tl \l__spath_tmpa_tl
-      \spath_save_path:cV
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \l__spath_tmpa_tl
+\cs_new_protected_nopar:Npn \__tikzspath_use_path:n #1
+{
+  \tl_set:Nn \l__tikzspath_joinpath_tl {#1}
+  \spath_get_current_path:N \l__tikzspath_current_tl
+
+  \bool_if:NT \l__tikzspath_reverse_bool
+  {
+    \spath_reverse:N \l__tikzspath_joinpath_tl
+  }
+
+  \bool_if:NT \l__tikzspath_current_transformation_bool
+  {
+    \pgfgettransform \l__tikzspath_tmpa_tl
+    \spath_transform:NV
+    \l__tikzspath_joinpath_tl
+    \l__tikzspath_tmpa_tl
+  }
+
+  \tl_if_empty:NF \l__tikzspath_transformation_tl
+  {
+    \group_begin:
+    \pgftransformreset
+    \__tikzspath_tikzset:V \l__tikzspath_transformation_tl
+    \pgfgettransform \l__tikzspath_tmpa_tl
+    \tl_gset:Nn \g__tikzspath_smuggle_tl
+    {
+      \spath_transform:Nnnnnnn
+      \l__tikzspath_joinpath_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
+    \tl_gput_right:NV \g__tikzspath_smuggle_tl \l__tikzspath_tmpa_tl
+    \group_end:
+    \tl_use:N \g__tikzspath_smuggle_tl
+  }
+
+  \bool_if:NT \l__tikzspath_move_bool
+  {
+    \tl_if_empty:NTF \l__tikzspath_current_tl
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl { {0pt} {0pt} }
     }
-  },
-  clone/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
     {
-      \tl_clear_new:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \tl_set_eq:cc
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \spath_finalpoint:NV
+      \l__tikzspath_tmpc_tl
+      \l__tikzspath_current_tl
     }
+    \spath_translate_to:NV \l__tikzspath_joinpath_tl \l__tikzspath_tmpc_tl
+  }
+
+  \tl_if_empty:NTF \l__tikzspath_current_tl
+  {
+    \tl_if_empty:NTF \l__tikzspath_joinpath_tl
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+      \tl_set_eq:NN \l__tikzspath_current_tl \c_spath_moveto_tl
+      \tl_put_right:Nn \l__tikzspath_current_tl {{0pt}{0pt}}
     }
-  },
-  clone~ global/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
     {
-      \tl_gclear_new:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \tl_gset_eq:cc
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \tl_set_eq:NN \l__tikzspath_current_tl \l__tikzspath_joinpath_tl
     }
+  }
+  {
+
+    \tl_clear:N \l__tikzspath_tmpa_tl
+    \tl_set:Nn \l__tikzspath_tmpa_tl {spath_}
+
+    \tl_put_right:Nn \l__tikzspath_tmpa_tl {append}
+
+    \bool_if:NT \l__tikzspath_weld_bool
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+      \tl_put_right:Nn \l__tikzspath_tmpa_tl {_no_move}
+      \spath_numberofcomponents:NV \l__tikzspath_tmpa_int \l__tikzspath_joinpath_tl
+      \int_compare:nT {\l__tikzspath_tmpa_int == 1}
+      {
+        \bool_set_false:N \l_spath_movetorelevant_bool
+      }
     }
-  },
-  save~ to~ aux/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \tl_put_right:Nn \l__tikzspath_tmpa_tl {:NV}
+
+    \use:c {\tl_use:N \l__tikzspath_tmpa_tl }
+    \l__tikzspath_current_tl
+    \l__tikzspath_joinpath_tl
+  }
+
+  \spath_set_current_path:N \l__tikzspath_current_tl
+  \spath_set_tikz_data:V \l__tikzspath_joinpath_tl
+}
+\cs_generate_variant:Nn \__tikzspath_use_path:n {V, v}
+\cs_new_protected_nopar:Npn \__tikzspath_join_with:Nn #1#2
+{
+  \tl_set:Nn \l__tikzspath_joinpath_tl {#2}
+
+  \bool_if:NT \l__tikzspath_reverse_bool
+  {
+    \spath_reverse:N \l__tikzspath_joinpath_tl
+  }
+
+  \tl_if_empty:NF \l__tikzspath_transformation_tl
+  {
+    \group_begin:
+    \pgftransformreset
+    \__tikzspath_tikzset:V \l__tikzspath_transformation_tl
+    \pgfgettransform \l__tikzspath_tmpa_tl
+    \tl_gset:Nn \g__tikzspath_smuggle_tl
     {
-      \spath_save_to_aux:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      \spath_transform:Nnnnnnn
+      \l__tikzspath_joinpath_tl
     }
+    \tl_gput_right:NV \g__tikzspath_smuggle_tl \l__tikzspath_tmpa_tl
+    \group_end:
+    \tl_use:N \g__tikzspath_smuggle_tl
+  }
+
+  \bool_if:NT \l__tikzspath_move_bool
+  {
+    \spath_finalpoint:NV
+    \l__tikzspath_tmpc_tl
+    #1
+    \spath_translate_to:NV \l__tikzspath_joinpath_tl \l__tikzspath_tmpc_tl
+  }
+
+  \tl_clear:N \l__tikzspath_tmpa_tl
+  \tl_set:Nn \l__tikzspath_tmpa_tl {spath_}
+
+  \bool_if:NT \l__tikzspath_global_bool
+  {
+    \tl_put_right:Nn \l__tikzspath_tmpa_tl {g}
+  }
+
+  \tl_put_right:Nn \l__tikzspath_tmpa_tl {append}
+
+  \bool_if:NT \l__tikzspath_weld_bool
+  {
+    \tl_put_right:Nn \l__tikzspath_tmpa_tl {_no_move}
+  }
+  \tl_put_right:Nn \l__tikzspath_tmpa_tl {:NV}
+
+  \cs_if_exist:cF {\tl_use:N \l__tikzspath_tmpa_tl}
+  {
+    \tl_show:N \l__tikzspath_tmpa_tl
+  }
+
+  \use:c {\tl_use:N \l__tikzspath_tmpa_tl } #1
+  \l__tikzspath_joinpath_tl
+}
+\cs_generate_variant:Nn \__tikzspath_join_with:Nn {cv, cn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with_aux:nnn #1#2#3
+{
+  \group_begin:
+  \tl_set:Nn \l__tikzspath_tmpc_tl {#1}
+  \tl_if_empty:nT {#3}
+  {
+    \spath_spot_weld_components:N \l__tikzspath_tmpc_tl
+  }
+
+  \spath_numberofcomponents:NV \l__tikzspath_tmpa_int \l__tikzspath_tmpc_tl
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpb_seq \l__tikzspath_tmpa_int {#3}
+
+  \spath_components_to_seq:NV \l__tikzspath_tmpa_seq \l__tikzspath_tmpc_tl
+
+  \seq_pop_left:NN \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+  \seq_pop_left:NN \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_tl
+
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \int_compare:nTF
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      ##1 == \l__tikzspath_tmpb_tl
     }
-  },
-  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}
+      \seq_pop_left:NNF \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_tl
+      {
+        \tl_set:Nn \l__tikzspath_tmpb_tl {-1}
+      }
+      \spath_splice_between:Nnn \l__tikzspath_tmpa_tl {#2} {##2}
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_put_right:Nn \l__tikzspath_tmpa_tl {##2}
     }
-  },
-  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_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with:Nnnn #1#2#3#4
+{
+  \__tikzspath_join_components_with_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with:Nnn #1#2#3
+{
+  \__tikzspath_join_components_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_with:Nnnn #1#2#3#4
+{
+  \__tikzspath_join_components_with_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_with:Nnn #1#2#3
+{
+  \__tikzspath_gjoin_components_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_upright_with_aux:nnn #1#2#3
+{
+  \group_begin:
+  \tl_set:Nn \l__tikzspath_tmpc_tl {#1}
+  \tl_if_empty:nT {#3}
+  {
+    \spath_spot_weld_components:N \l__tikzspath_tmpc_tl
+  }
 
-    \tl_if_exist:cTF
+  \spath_numberofcomponents:NV \l__tikzspath_tmpa_int \l__tikzspath_tmpc_tl
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpb_seq \l__tikzspath_tmpa_int {#3}
+
+  \spath_components_to_seq:NV \l__tikzspath_tmpa_seq \l__tikzspath_tmpc_tl
+
+  \seq_pop_left:NN \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+  \seq_pop_left:NN \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_tl
+
+  \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+  \spath_transform:NVnnnnnn \l__tikzspath_tmpd_tl \l__tikzspath_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \int_compare:nTF
     {
-      \tl_use:N \l__spath_prefix_tl
-      \tl_use:N \l__spath_joinpath_tl
-      \tl_use:N \l__spath_suffix_tl
+      ##1 == \l__tikzspath_tmpb_tl
     }
     {
-      \tl_if_empty:cT
+      \seq_pop_left:NNF \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_tl
       {
-        \tl_use:N \l__spath_prefix_tl
-        \tl_use:N \l__spath_joinpath_tl
-        \tl_use:N \l__spath_suffix_tl
+        \tl_set:Nn \l__tikzspath_tmpb_tl {-1}
       }
+
+      \spath_finalpoint:NV \l__tikzspath_tmpe_tl \l__tikzspath_tmpa_tl
+      \spath_initialpoint:Nn \l__tikzspath_tmpf_tl {##2}
+
+      \dim_compare:nTF
       {
-        \msg_warning:nnn { spath3 } { empty soft path } { #1 }
+        \tl_item:Nn \l__tikzspath_tmpe_tl {1}
+        >
+        \tl_item:Nn \l__tikzspath_tmpf_tl {1}
       }
-      \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
+        \spath_splice_between:NVn
+        \l__tikzspath_tmpa_tl
+        \l__tikzspath_tmpd_tl
+        {##2}
       }
-      \spath_get_current_path:N \l__spath_current_tl
-
-      \bool_if:NT \l__spath_reverse_bool
       {
-        \spath_reverse:N \l__spath_joinpath_tl
+        \spath_splice_between:NVn
+        \l__tikzspath_tmpa_tl
+        \l__tikzspath_tmpc_tl
+        {##2}
       }
+    }
+    {
+      \tl_put_right:Nn \l__tikzspath_tmpa_tl {##2}
+    }
+  }
+  \tl_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_upright_with:Nnnn #1#2#3#4
+{
+  \__tikzspath_join_components_upright_with_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_upright_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_upright_with:Nnn #1#2#3
+{
+  \__tikzspath_join_components_upright_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_upright_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_upright_with:Nnnn #1#2#3#4
+{
+  \__tikzspath_join_components_upright_with_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_upright_with:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_upright_with:Nnn #1#2#3
+{
+  \__tikzspath_gjoin_components_upright_with:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_upright_with:Nnn {cvV}
+\cs_new_protected_nopar:Npn \__tikzspath_get_components_aux:n #1
+{
+  \clist_gclear_new:N \g__tikzspath_output_clist
+  \spath_components_to_seq:Nn \l__tikzspath_tmpa_seq {#1}
 
-      \tl_if_empty:NF \l__spath_transformation_tl
+  \seq_map_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \spath_anonymous:N \l__tikzspath_tmpa_tl
+    \tl_new:c {\__tikzspath_path_name:V \l__tikzspath_tmpa_tl}
+    \tl_set:cn {\__tikzspath_path_name:V \l__tikzspath_tmpa_tl} {##1}
+    \clist_gput_right:NV \g__tikzspath_output_clist \l__tikzspath_tmpa_tl
+  }
+}
+\cs_new_protected_nopar:Npn \__tikzspath_get_components:Nn #1#2
+{
+  \clist_clear_new:N #1
+  \__tikzspath_get_components_aux:n {#2}
+  \clist_set_eq:NN #1 \g__tikzspath_output_clist
+  \clist_gclear:N \g__tikzspath_output_clist
+}
+\cs_generate_variant:Nn \__tikzspath_get_components:Nn {NV, Nv}
+\cs_new_protected_nopar:Npn \__tikzspath_gget_components:Nn #1#2
+{
+  \clist_gclear_new:N #1
+  \__tikzspath_get_components_aux:n {#2}
+  \clist_gset_eq:NN #1 \g__tikzspath_output_clist
+  \clist_gclear:N \g__tikzspath_output_clist
+}
+\cs_generate_variant:Nn \__tikzspath_gget_components:Nn {NV, Nv}
+\cs_new_protected_nopar:Npn \__tikzspath_render_components:nn #1#2
+{
+  \group_begin:
+  \spath_components_to_seq:Nn \l__tikzspath_tmpa_seq {#2}
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \spath_tikz_path:nn
+    {
+      every~ spath~ component/.try,
+      spath ~component~ ##1/.try,
+      spath ~component/.try={##1},
+      every~ #1~ component/.try,
+      #1 ~component~ ##1/.try,
+      #1 ~component/.try={##1},
+    }
+    {
+      ##2
+    }
+  }
+  \group_end:
+}
+\cs_generate_variant:Nn \__tikzspath_render_components:nn {nv}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_components_aux:nnn #1#2#3
+{
+  \group_begin:
+  \spath_numberofcomponents:Nn \l__tikzspath_tmpa_int {#1}
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_int {#3}
+
+  \tl_if_empty:nT {#3}
+  {
+    \seq_pop_right:NN \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+  }
+
+  \seq_clear:N \l__tikzspath_tmpb_seq
+  \seq_map_inline:Nn \l__tikzspath_tmpa_seq {
+    \seq_put_right:Nx
+    \l__tikzspath_tmpb_seq
+    {\int_eval:n
       {
-        \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
+        \int_mod:nn { ##1 }{ \l__tikzspath_tmpa_int } + 1
       }
+    }
+  }
 
-      \bool_if:NT \l__spath_move_bool
+  \spath_components_to_seq:Nn \l__tikzspath_tmpc_seq {#1}
+
+  \seq_clear:N \l__tikzspath_tmpd_seq
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpc_seq
+  {
+    \tl_set:Nn \l__tikzspath_tmpa_tl {##2}
+    \seq_if_in:NnT \l__tikzspath_tmpa_seq {##1}
+    {
+      \spath_shorten_at_end:Nn \l__tikzspath_tmpa_tl {(#2)/2}
+    }
+    \seq_if_in:NnT \l__tikzspath_tmpb_seq {##1}
+    {
+      \spath_shorten_at_start:Nn \l__tikzspath_tmpa_tl {(#2)/2}
+    }
+    \seq_put_right:NV \l__tikzspath_tmpd_seq \l__tikzspath_tmpa_tl
+  }
+  \tl_gset:Nx \g__tikzspath_output_tl {\seq_use:Nn \l__tikzspath_tmpd_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_components:Nnnn #1#2#3#4
+{
+  \__tikzspath_insert_gaps_after_components_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_insert_gaps_after_components:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_components:Nnn #1#2#3
+{
+  \__tikzspath_insert_gaps_after_components:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_insert_gaps_after_components:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \__tikzspath_ginsert_gaps_after_components:Nnnn #1#2#3#4
+{
+  \__tikzspath_insert_gaps_after_components_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_ginsert_gaps_after_components:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_ginsert_gaps_after_components:Nnn #1#2#3
+{
+  \__tikzspath_ginsert_gaps_after_components:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_ginsert_gaps_after_components:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_segments_aux:nnn #1#2#3
+{
+  \group_begin:
+  \spath_reallength:Nn \l__tikzspath_tmpa_int {#1}
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_int {#3}
+
+  \tl_if_empty:nT {#3}
+  {
+    \seq_pop_right:NN \l__tikzspath_tmpb_seq \l__tikzspath_tmpa_tl
+  }
+
+  \seq_clear:N \l__tikzspath_tmpb_seq
+  \seq_map_inline:Nn \l__tikzspath_tmpa_seq {
+    \seq_put_right:Nx
+    \l__tikzspath_tmpb_seq
+    {\int_eval:n
       {
-        \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
+        \int_mod:nn { ##1 }{ \l__tikzspath_tmpa_int } + 1
       }
+    }
+  }
 
-      \tl_if_empty:NTF \l__spath_current_tl
+  \spath_segments_to_seq:Nn \l__tikzspath_tmpc_seq {#1}
+
+  \seq_clear:N \l__tikzspath_tmpd_seq
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpc_seq
+  {
+    \tl_set:Nn \l__tikzspath_tmpa_tl {##2}
+    \seq_if_in:NnT \l__tikzspath_tmpa_seq {##1}
+    {
+      \spath_shorten_at_end:Nn \l__tikzspath_tmpa_tl {(#2)/2}
+    }
+    \seq_if_in:NnT \l__tikzspath_tmpb_seq {##1}
+    {
+      \spath_shorten_at_start:Nn \l__tikzspath_tmpa_tl {(#2)/2}
+    }
+    \seq_put_right:NV \l__tikzspath_tmpd_seq \l__tikzspath_tmpa_tl
+  }
+  \tl_gset:Nx \g__tikzspath_output_tl {\seq_use:Nn \l__tikzspath_tmpd_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_segments:Nnnn #1#2#3#4
+{
+  \__tikzspath_insert_gaps_after_segments_aux:nnn {#2}{#3}{#4}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_insert_gaps_after_segments:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_insert_gaps_after_segments:Nnn #1#2#3
+{
+  \__tikzspath_insert_gaps_after_segments:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_insert_gaps_after_segments:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \__tikzspath_ginsert_gaps_after_segments:Nnnn #1#2#3#4
+{
+  \__tikzspath_insert_gaps_after_segments_aux:nnn {#2}{#3}{#4}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_ginsert_gaps_after_segments:Nnnn {NVnn}
+\cs_new_protected_nopar:Npn \__tikzspath_ginsert_gaps_after_segments:Nnn #1#2#3
+{
+  \__tikzspath_ginsert_gaps_after_segments:NVnn #1#1{#2}{#3}
+}
+\cs_generate_variant:Nn \__tikzspath_ginsert_gaps_after_segments:Nnn {cnn, cVV}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_aux:nn #1#2
+{
+  \group_begin:
+
+  \tl_set:Nn \l__tikzspath_tmpa_tl {#1}
+  \spath_numberofcomponents:NV \l__tikzspath_tmpa_int \l__tikzspath_tmpa_tl
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_int {#2}
+
+  \seq_reverse:N \l__tikzspath_tmpa_seq
+
+  \seq_map_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \spath_join_component:Nn \l__tikzspath_tmpa_tl {##1}
+  }
+  \tl_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components:Nnn #1#2#3
+{
+  \__tikzspath_join_components_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_join_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components:Nn #1#2
+{
+  \__tikzspath_join_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_join_components:Nn {cn}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components:Nnn #1#2#3
+{
+  \__tikzspath_join_components_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components:Nn #1#2
+{
+  \__tikzspath_gjoin_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components:Nn {cn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with_bezier_aux:nn #1#2
+{
+  \group_begin:
+  \tl_set:Nn \l__tikzspath_tmpc_tl {#1}
+  \tl_if_empty:nT {#2}
+  {
+    \spath_spot_weld_components:N \l__tikzspath_tmpc_tl
+  }
+
+  \spath_numberofcomponents:NV \l__tikzspath_tmpa_int \l__tikzspath_tmpc_tl
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpb_seq \l__tikzspath_tmpa_int {#2}
+
+  \spath_components_to_seq:NV \l__tikzspath_tmpa_seq \l__tikzspath_tmpc_tl
+
+  \seq_pop_left:NN \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+  \seq_pop_left:NN \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_tl
+
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpa_seq
+  {
+    \int_compare:nTF
+    {
+      ##1 == \l__tikzspath_tmpb_tl
+    }
+    {
+      \seq_pop_left:NNF \l__tikzspath_tmpb_seq \l__tikzspath_tmpb_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_set:Nn \l__tikzspath_tmpb_tl {-1}
       }
-      {
+      \spath_curve_between:Nn \l__tikzspath_tmpa_tl {##2}
+    }
+    {
+      \tl_put_right:Nn \l__tikzspath_tmpa_tl {##2}
+    }
+  }
+  \tl_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpa_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with_bezier:Nnn #1#2#3
+{
+  \__tikzspath_join_components_with_bezier_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_with_bezier:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_join_components_with_bezier:Nn #1#2
+{
+  \__tikzspath_join_components_with_bezier:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_join_components_with_bezier:Nn {cV}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_with_bezier:Nnn #1#2#3
+{
+  \__tikzspath_join_components_with_bezier_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_with_bezier:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_gjoin_components_with_bezier:Nn #1#2
+{
+  \__tikzspath_gjoin_components_with_bezier:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_gjoin_components_with_bezier:Nn {cV}
+\cs_new_protected_nopar:Npn \__tikzspath_remove_components_aux:nn #1#2
+{
+  \group_begin:
 
-        \tl_clear:N \l__spath_tmpa_tl
-        \tl_set:Nn \l__spath_tmpa_tl {spath_}
+  \spath_numberofcomponents:Nn \l__tikzspath_tmpa_int {#1}
+  \__tikzspath_seq_from_foreach:NVn \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_int {#2}
 
-        \tl_put_right:Nn \l__spath_tmpa_tl {append}
+  \spath_components_to_seq:Nn \l__tikzspath_tmpb_seq {#1}
 
-        \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}
+  \seq_pop_left:NNF \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+  {
+    \tl_clear:N \l__tikzspath_tmpa_tl
+  }
 
-        \use:c {\tl_use:N \l__spath_tmpa_tl }
-        \l__spath_current_tl
-        \l__spath_joinpath_tl
+  \seq_clear:N \l__tikzspath_tmpc_seq
+  \seq_map_indexed_inline:Nn \l__tikzspath_tmpb_seq
+  {
+    \tl_set:Nn \l__tikzspath_tmpb_tl {##1}
+    \tl_if_eq:NNTF \l__tikzspath_tmpb_tl \l__tikzspath_tmpa_tl
+    {
+      \seq_pop_left:NNF \l__tikzspath_tmpa_seq \l__tikzspath_tmpa_tl
+      {
+        \tl_clear:N \l__tikzspath_tmpa_tl
       }
+    }
+    {
+      \seq_put_right:Nn \l__tikzspath_tmpc_seq {##2}
+    }
+  }
 
-      \spath_set_current_path:N \l__spath_current_tl
-      \spath_set_tikz_data:V \l__spath_joinpath_tl
+  \tl_gset:Nx \g__tikzspath_output_tl {\seq_use:Nn \l__tikzspath_tmpc_seq {} }
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_remove_components:Nnn #1#2#3
+{
+  \__tikzspath_remove_components_aux:nn {#2}{#3}
+  \tl_set_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_remove_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_remove_components:Nn #1#2
+{
+  \__tikzspath_remove_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_remove_components:Nn {cn}
+\cs_new_protected_nopar:Npn \__tikzspath_gremove_components:Nnn #1#2#3
+{
+  \__tikzspath_remove_components_aux:nn {#2}{#3}
+  \tl_gset_eq:NN #1 \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_gremove_components:Nnn {NVn}
+\cs_new_protected_nopar:Npn \__tikzspath_gremove_components:Nn #1#2
+{
+  \__tikzspath_gremove_components:NVn #1#1{#2}
+}
+\cs_generate_variant:Nn \__tikzspath_gremove_components:Nn {cn}
+\cs_new_protected_nopar:Npn \__tikzspath_transform_to_aux:nn #1#2
+{
+  \group_begin:
+  \spath_reallength:Nn \l__tikzspath_tmpa_int {#2}
+
+  \tl_set:Nx \l__tikzspath_tmpb_tl
+  {\fp_to_decimal:n {(#1) * (\l__tikzspath_tmpa_int)}}
+  \spath_transformation_at:NnV \l__tikzspath_tmpc_tl {#2} \l__tikzspath_tmpb_tl
+  \tl_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpc_tl
+  \group_end:
+}
+\cs_new_protected_nopar:Npn \__tikzspath_transform_to:nn #1#2
+{
+  \__tikzspath_transform_to_aux:nn {#1}{#2}
+  \exp_last_unbraced:NV \pgfsettransformentries \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_transform_to:nn {nv}
+\cs_new_protected_nopar:Npn \__tikzspath_transform_upright_to:nn #1#2
+{
+  \__tikzspath_transform_to_aux:nn {#1}{#2}
+  \fp_compare:nT { \tl_item:Nn \g__tikzspath_output_tl {4} < 0}
+  {
+    \tl_gset:Nx \g__tikzspath_output_tl
+    {
+      { \fp_eval:n { - (\tl_item:Nn \g__tikzspath_output_tl {1})} }
+      { \fp_eval:n { - (\tl_item:Nn \g__tikzspath_output_tl {2})} }
+      { \fp_eval:n { - (\tl_item:Nn \g__tikzspath_output_tl {3})} }
+      { \fp_eval:n { - (\tl_item:Nn \g__tikzspath_output_tl {4})} }
+      { \tl_item:Nn \g__tikzspath_output_tl {5} }
+      { \tl_item:Nn \g__tikzspath_output_tl {6} }
     }
+  }
+  \exp_last_unbraced:NV \pgfsettransformentries \g__tikzspath_output_tl
+  \tl_gclear:N \g__tikzspath_output_tl
+}
+\cs_generate_variant:Nn \__tikzspath_transform_upright_to:nn {nv}
+\tikzset{
+  spath/.is~family,
+  spath/.cd,
+  set~ prefix/.store~ in=\l__tikzspath_prefix_tl,
+  prefix/.is~choice,
+  prefix/default/.style={
+    /tikz/spath/set~ prefix=tikz at intersect@path at name@
+  },
+  set~ suffix/.store~ in=\l__tikzspath_suffix_tl,
+  suffix/.is~choice,
+  suffix/default/.style={
+    /tikz/spath/set~ suffix={}
+  },
+  set~ name/.style={
+    /tikz/spath/prefix=#1,
+    /tikz/spath/suffix=#1
+  },
+  at~ end~ path~ construction/.code={
+    \tl_put_right:Nn \l__tikzspath_tikzpath_finish_tl {#1}
+  },
+  save/.code={
+    \tikz at addmode{
+      \spath_get_current_path:N \l__tikzspath_tmpa_tl
+      \spath_bake_round:NV \l__tikzspath_tmpa_tl \l__tikzspath_tmpa_tl
+      \spath_bake_shorten:NV \l__tikzspath_tmpa_tl \l__tikzspath_tmpa_tl
+      \spath_save_path:cV {\__tikzspath_path_name:n {#1}}
+      \l__tikzspath_tmpa_tl
+    }
+  },
+  save~ global/.code={
+    \tikz at addmode{
+      \spath_get_current_path:N \l__tikzspath_tmpa_tl
+      \spath_bake_round:NV \l__tikzspath_tmpa_tl \l__tikzspath_tmpa_tl
+      \spath_bake_shorten:NV \l__tikzspath_tmpa_tl \l__tikzspath_tmpa_tl
+      \spath_gsave_path:cV {\__tikzspath_path_name:n {#1}}
+      \l__tikzspath_tmpa_tl
+    }
+  },
+  clone/.code~ 2~ args={
+    \__tikzspath_maybe_current_path:nn
     {
-      \msg_warning:nnx
-      { spath3 }
-      { missing soft path }
-      {\tl_use:N \l__spath_joinpath_tl }
+      \__tikzspath_check_path:nnn {
+        \tl_clear_new:c {\__tikzspath_path_name:n {#1}}
+        \tl_set_eq:cc {\__tikzspath_path_name:n {#1}}
+      }
     }
+    {#2}{}
   },
+  clone~ global/.code~ 2~ args={
+    \__tikzspath_maybe_current_path:nn
+    {
+      \__tikzspath_check_path:nnn {
+        \tl_gclear_new:c {\__tikzspath_path_name:n {#1}}
+        \tl_gset_eq:cc {\__tikzspath_path_name:n {#1}}
+      }
+    }
+    {#2}{}
+  },
+  save~ to~ aux/.code={
+    \__tikzspath_maybe_current_path:nn
+    {
+      \__tikzspath_check_path:nnn {
+        \spath_save_to_aux:c
+      }
+    }
+    {#1}
+    {}
+  },
+  export~ to~ svg/.code={
+    \__tikzspath_maybe_current_path:nn
+    {
+      \__tikzspath_check_path:nnn {
+        \spath_export_to_svg:nv {#1}
+      }
+    }
+    {#1}
+    {}
+  },
+  use/.code={
+    \bool_set_false:N \l__tikzspath_reverse_bool
+    \bool_set_false:N \l__tikzspath_weld_bool
+    \bool_set_false:N \l__tikzspath_move_bool
+    \bool_set_false:N \l__tikzspath_current_transformation_bool
+    \bool_set_true:N \l_spath_movetorelevant_bool
+    \tl_clear:N \l__tikzspath_joinpath_tl
+    \tl_clear:N \l__tikzspath_transformation_tl
+    \tikzset{
+      spath/join/.cd,
+      #1
+    }
+
+    \__tikzspath_check_path:nVn
+    {
+      \__tikzspath_use_path:v
+    } \l__tikzspath_joinpath_tl {}
+
+  },
   restore/.style={/tikz/spath/use={#1}},
   restore~ reverse/.style={/tikz/spath/use={reverse, #1}},
   append/.style={/tikz/spath/use={move, weld, #1}},
@@ -329,914 +1127,534 @@
   insert~ reverse/.style={/tikz/spath/use={reverse, #1}},
   show~current~path/.code={
     \tikz at addmode{
-      \pgfsyssoftpath at getcurrentpath\l__spath_tmpa_tl
+      \pgfsyssoftpath at getcurrentpath\l__tikzspath_tmpa_tl
       \iow_term:n {---~ current~ soft~ path~ ---}
-      \spath_show:V \l__spath_tmpa_tl
+      \spath_show:V \l__tikzspath_tmpa_tl
     }
   },
   show/.code={
-    \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}
-      {
-        \msg_warning:nnn { spath3 } { empty soft path } { #1 }
-      }
-      {
-        \iow_term:n {---~ soft~ path~ #1~ ---}
-        \spath_show:v
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    \__tikzspath_check_path:nnn {
+      \iow_term:n {---~ soft~ path~ #1~ ---}
+      \spath_show:v
+    } {#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__tikzspath_reverse_bool
+    \bool_set_false:N \l__tikzspath_weld_bool
+    \bool_set_false:N \l__tikzspath_move_bool
+    \bool_set_false:N \l__tikzspath_global_bool
+    \bool_set_false:N \l__tikzspath_current_transformation_bool
+    \tl_clear:N \l__tikzspath_joinpath_tl
+    \tl_clear:N \l__tikzspath_transformation_tl
+    \tikzset{
+      spath/join/.cd,
+      #2
+    }
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \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
+      \__tikzspath_check_two_paths:nnVn
       {
-        \tl_use:N \l__spath_prefix_tl
-        \tl_use:N \l__spath_joinpath_tl
-        \tl_use:N \l__spath_suffix_tl
+        \__tikzspath_join_with:cv
       }
-      {
-        \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}
-        \l__spath_joinpath_tl
-      }
-      {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        {\tl_use:N \l__spath_joinpath_tl }
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { \l__tikzspath_joinpath_tl {} }
   },
   spot~ weld/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_spot_weld_components:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_spot_weld_components:c
+      }
+    } {#1} { {} }
   },
   spot~ weld~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_spot_gweld_components:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_spot_gweld_components:c
+      }
+    } {#1} { {} }
   },
   reverse/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_reverse:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_reverse:c
+      }
+    } {#1} { {} }
   },
   reverse~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_reverse:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_greverse:c
+      }
+    } {#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}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \__spath_process_tikz_point:Nn \l__spath_tmpa_tl {#2}
-      \__spath_process_tikz_point:Nn \l__spath_tmpb_tl {#3}
-      \spath_span:cVV
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \l__spath_tmpa_tl \l__spath_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \__tikzspath_process_tikz_point:Nn \l__tikzspath_tmpa_tl {#2}
+        \__tikzspath_process_tikz_point:Nn \l__tikzspath_tmpb_tl {#3}
+        \spath_span:cVV
+      }
+    } {#1} { {} \l__tikzspath_tmpa_tl \l__tikzspath_tmpb_tl }
   },
   span~ global/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \__spath_process_tikz_point:Nn \l__spath_tmpa_tl {#2}
-      \__spath_process_tikz_point:Nn \l__spath_tmpb_tl {#3}
-      \spath_gspan:cVV
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \l__spath_tmpa_tl \l__spath_tmpb_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \__tikzspath_process_tikz_point:Nn \l__tikzspath_tmpa_tl {#2}
+        \__tikzspath_process_tikz_point:Nn \l__tikzspath_tmpb_tl {#3}
+        \spath_span:cVV
+      }
+    } {#1} { {} \l__tikzspath_tmpa_tl \l__tikzspath_tmpb_tl }
   },
   to/.style={
     to~path={
       [
         spath/span={#1}{(\tikztostart)}{(\tikztotarget)},
-        spath/append~no~move={#1},
+        spath/use={#1,weld},
       ]
       \tikztonodes
     }
   },
   splice/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_check_three_paths:nnnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #3 \tl_use:N \l__spath_suffix_tl}
-        {
-          \spath_splice_between:cvv
-          {\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}
-          {\tl_use:N \l__spath_prefix_tl #3 \tl_use:N \l__spath_suffix_tl}
-        }
-        {
-          \msg_warning:nnn { spath3 } { missing soft path } { #3 }
-        }
+        \spath_splice_between:cvv
       }
+    } {#1} { {#2} {#3} {} }
+  },
+  splice~ global/.code ~n~ args={3}{
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_three_paths:nnnnn
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \spath_gsplice_between:cvv
       }
+    } {#1} { {#2} {#3} {} }
+  },
+  join~ components~ with/.code~2~args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_tl
     }
-  },
-  splice~ global/.code ~n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_check_two_paths:nnVn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #3 \tl_use:N \l__spath_suffix_tl}
-        {
-          \spath_gsplice_between:cvv
-          {\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}
-          {\tl_use:N \l__spath_prefix_tl #3 \tl_use:N \l__spath_suffix_tl}
-        }
-        {
-          \msg_warning:nnn { spath3 } { missing soft path } { #3 }
-        }
+        \__tikzspath_join_components_with:cvV
       }
+    } {#1} { \l__tikzspath_tmpc_tl {} \l__tikzspath_tmpd_tl  }
+  },
+  join~ components~ globally~ with/.code~2~args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_tl
+    }
+
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_two_paths:nnVn
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \__tikzspath_gjoin_components_with:cvV
       }
+    } {#1} { \l__tikzspath_tmpc_tl {} \l__tikzspath_tmpd_tl  }
+  },
+  join~ components~ upright~ with/.code~2~args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_tl
     }
-  },
-  join~ components~ with/.code~2~args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \__tikzspath_check_two_paths:nnVn
       {
-        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+        \__tikzspath_join_components_upright_with:cvV
       }
-      {
-        \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}
-        }
+    } {#1} { \l__tikzspath_tmpc_tl {} \l__tikzspath_tmpd_tl  }
+  },
+  join~ components~ globally~ upright~ with/.code~2~args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_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_set_eq:cN
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-        \l__spath_tmpa_tl
-      }
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_two_paths:nnVn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l__spath_tmpc_tl }
+        \__tikzspath_gjoin_components_upright_with:cvV
       }
+    } {#1} { \l__tikzspath_tmpc_tl {} \l__tikzspath_tmpd_tl  }
+  },
+  join~ components~ with~ bezier/.code={
+    \tl_if_head_is_group:nTF {#1}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#1} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#1} {2} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#1}
+      \tl_clear:N \l__tikzspath_tmpd_tl
     }
-  },
-  join~ components~ globally~ with/.code~2~args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+
+    \__tikzspath_maybe_current_path_reuse:nVn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+        \__tikzspath_join_components_with_bezier:cV
       }
+    } \l__tikzspath_tmpc_tl { {} \l__tikzspath_tmpd_tl }
+  },
+  join~ components~ globally~ with~ bezier/.code~2~args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nn \l__spath_tmpc_tl {#2}
-        \tl_clear:N \l__spath_tmpd_tl
+        \__tikzspath_gjoin_components_with_bezier:cn
       }
-      \tl_if_exist:cTF
+    } {#1} { {} {#2} }
+  },
+  close/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_use:N \l__spath_prefix_tl
-        \tl_use:N \l__spath_tmpc_tl
-        \tl_use:N \l__spath_suffix_tl
+        \spath_close:c
       }
+    } {#1} { {} }
+  },
+  close~ globally/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \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
+        \spath_gclose:c
       }
+    } {#1} { {} }
+  },
+  open/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l__spath_tmpc_tl }
+        \spath_open:c
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#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}
+  open~ globally/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+        \spath_gopen:c
       }
+    } {#1} { {} }
+  },
+  adjust~ and~ close/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nn \l__spath_tmpc_tl {#2}
-        \tl_clear:N \l__spath_tmpd_tl
+        \spath_adjust_close:c
       }
-      \tl_if_exist:cTF
+    } {#1} { {} }
+  },
+  adjust~ and~ close~ globally/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_use:N \l__spath_prefix_tl
-        \tl_use:N \l__spath_tmpc_tl
-        \tl_use:N \l__spath_suffix_tl
+        \spath_adjust_gclose:c
       }
+    } {#1} { {} }
+  },
+  close~ with/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_two_paths:nnnn
       {
-        \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_set_eq:cN
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-        \l__spath_tmpa_tl
+        \spath_close_with:cv
       }
+    } {#1} { {#2} {} }
+  },
+  close~ globally~ with/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_two_paths:nnnn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l__spath_tmpc_tl }
+        \spath_gclose_with:cv
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {#2} {} }
   },
-  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}
+  close~ with~ curve/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_head_is_group:nTF {#2}
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+        \spath_close_with_curve:c
       }
+    } {#1} { {} }
+  },
+  close~ globally~ with~ curve/.code={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nn \l__spath_tmpc_tl {#2}
-        \tl_clear:N \l__spath_tmpd_tl
+        \spath_gclose_with_curve:c
       }
-      \tl_if_exist:cTF
+    } {#1} { {} }
+  },
+  shorten~ at~ end/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \tl_use:N \l__spath_prefix_tl
-        \tl_use:N \l__spath_tmpc_tl
-        \tl_use:N \l__spath_suffix_tl
+        \spath_shorten_at_end:cn
       }
+    } {#1} { {} {#2} }
+  },
+  shorten~ at~ start/.code~ 2~ args ={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \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
+        \spath_shorten_at_start:cn
       }
+    } {#1} { {} {#2} }
+  },
+  shorten~ at~ both~ ends/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \msg_warning:nnx
-        { spath3 }
-        { missing soft path }
-        { \tl_use:N \l__spath_tmpc_tl }
+        \spath_shorten_at_both_ends:cn
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
-  close/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  shorten~ globally~ at~ end/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_close:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gshorten_at_end:cn
+      }
+    } {#1} { {} {#2} }
   },
-  close~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  shorten~ globally~ at~ start/.code~ 2~ args ={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gclose:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gshorten_at_start:cn
+      }
+    } {#1} { {} {#2} }
   },
-  close~ with/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  shorten~ globally~ at~ both~ ends/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_check_path:nnn
       {
-        \spath_close_with: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}
+        \spath_gshorten_at_both_ends:cn
       }
+    } {#1} { {} {#2} }
+  },
+  split~ at/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \spath_split_at_normalised:cn
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
-  close~ globally~ with/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ globally~ at/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_check_path:nnn
       {
-        \spath_gclose_with: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}
+        \spath_gsplit_at_normalised:cn
       }
+    } {#1} { {} {#2} }
+  },
+  split~ at~ into/.code~ n~ args={4}{
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+        \spath_split_at_normalised:ccvn {\__tikzspath_path_name:n {#1}}
+        {\__tikzspath_path_name:n {#2}}
       }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#3} { {} {#4} }
   },
-  shorten~ at~ end/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ globally~ at~ into/.code~ n~ args={4}{
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gsplit_at_normalised:ccvn {\__tikzspath_path_name:n {#1}}
+        {\__tikzspath_path_name:n {#2}}
+      }
+    } {#3} { {} {#4} }
   },
-  shorten~ at~ start/.code~ 2~ args ={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ at~ keep~ start/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_split_at_normalised_keep_start:cn
+      }
+    } {#1} { {} {#2} }
   },
-  shorten~ at~ both~ ends/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ globally~ at~ keep~ start/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gsplit_at_normalised_keep_start:cn
+      }
+    } {#1} { {} {#2} }
   },
-  shorten~ globally~ at~ end/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ at~ keep~ end/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gshorten_at_end:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_split_at_normalised_keep_end:cn
+      }
+    } {#1} { {} {#2} }
   },
-  shorten~ globally~ at~ start/.code~ 2~ args ={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+  split~ globally~ at~ keep~ end/.code~ 2~ args={
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gshorten_at_start:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gsplit_at_normalised_keep_end:cn
+      }
+    } {#1} { {} {#2} }
   },
-  shorten~ globally~ at~ both~ ends/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    {
-      \spath_shorten_at_end:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-      \spath_shorten_at_start:cn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl} {#2}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+  split~ at~ keep~ middle/.style~ n~ args={3}{
+    /tikz/spath/split~ at~ keep~ start={#1}{#3},
+    /tikz/spath/split~ at~ keep~ end={#1}{(#2)/(#3)},
   },
+  split~ globally~ at~ keep~ middle/.style~ n~ args={3}{
+    /tikz/spath/split~ globally~ at~ keep~ start={#1}{#3},
+    /tikz/spath/split~ globally~ at~ keep~ end={#1}{(#2)/(#3)},
+  },
   translate/.code~ n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_translate:cnn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{#2}{#3}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_translate:cnn
+      }
+    } {#1} { {} {#2}{#3} }
   },
   translate~ globally/.code~ n~ args={3}{
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gtranslate:cnn
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{#2}{#3}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gtranslate:cnn
+      }
+    } {#1} { {} {#2}{#3} }
   },
   normalise/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_normalise:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_normalise:c
+      }
+    } {#1} { {} }
   },
   normalise~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gnormalise:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gnormalise:c
+      }
+    } {#1} { {} }
   },
   transform/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \group_begin:
+    \pgftransformreset
+    \tikzset{#2}
+    \pgfgettransform \l__tikzspath_tmpa_tl
+    \tl_gset_eq:NN \g__tikzspath_smuggle_tl \l__tikzspath_tmpa_tl
+    \group_end:
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \pgftransformreset
-      \tikzset{#2}
-      \pgfgettransform \l__spath_tmpa_tl
-      \tl_gset:Nn \g__spath_smuggle_tl
+      \__tikzspath_check_path:nnn
       {
-        \spath_transform:cnnnnnn
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \spath_transform:cV
       }
-      \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl
-      \group_end:
-      \tl_use:N \g__spath_smuggle_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \g__tikzspath_smuggle_tl }
   },
   transform~globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \group_begin:
+    \pgftransformreset
+    \tikzset{#2}
+    \pgfgettransform \l__tikzspath_tmpa_tl
+    \tl_gset_eq:NN \g__tikzspath_smuggle_tl \l__tikzspath_tmpa_tl
+    \group_end:
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \pgftransformreset
-      \tikzset{#2}
-      \pgfgettransform \l__spath_tmpa_tl
-      \tl_gset:Nn \g__spath_smuggle_tl
+      \__tikzspath_check_path:nnn
       {
-        \spath_gtransform:cnnnnnn
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+        \spath_gtransform:cV
       }
-      \tl_gput_right:NV \g__spath_smuggle_tl \l__spath_tmpa_tl
-      \group_end:
-      \tl_use:N \g__spath_smuggle_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \g__tikzspath_smuggle_tl }
   },
-  split~ at~ intersections~ with/.code~ n~ args={2}{
+  split~ at~ intersections~ with/.code~ 2~ args={
     \tl_if_exist:cTF
     {
       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}
+      \__tikzspath_maybe_current_two_paths_reuse_first:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        \__tikzspath_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1248,23 +1666,13 @@
       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}
+      \__tikzspath_maybe_current_two_paths_reuse_first:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        \__tikzspath_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1276,23 +1684,13 @@
       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}
+      \__tikzspath_maybe_current_two_paths_reuse_both:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        \__tikzspath_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1304,23 +1702,13 @@
       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}
+      \__tikzspath_maybe_current_two_paths_reuse_both:nnnn
       {
-        \tl_if_exist:cTF
-        {\tl_use:N \l__spath_prefix_tl #2 \tl_use:N \l__spath_suffix_tl}
+        \__tikzspath_check_two_paths:nnnn
         {
           \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 } { #1 }
-      }
+      } {#1} {#2} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1332,15 +1720,13 @@
       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}
+      \__tikzspath_maybe_current_path_reuse:nnn
       {
-        \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 }
-      }
+        \__tikzspath_check_path:nnn
+        {
+          \spath_split_at_self_intersections:c
+        }
+      } {#1} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1352,15 +1738,13 @@
       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}
+      \__tikzspath_maybe_current_path_reuse:nnn
       {
-        \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 }
-      }
+        \__tikzspath_check_path:nnn
+        {
+          \spath_gsplit_at_self_intersections:c
+        }
+      } {#1} { {} }
     }
     {
       \msg_warning:nn { spath3 } { load intersections }
@@ -1367,612 +1751,321 @@
     }
   },
   get~ components~ of/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path:nn
     {
-      \clist_clear_new:N #2
-      \spath_components_to_seq:Nv
-      \l__spath_tmpa_seq
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \seq_map_inline:Nn \l__spath_tmpa_seq
-      {
-        \tl_new:c
-        {
-          \tl_use:N \l__spath_prefix_tl
-          anonymous_\int_use:N \g__spath_anon_int
-          \tl_use:N \l__spath_suffix_tl
-        }
-        \tl_set:cn
-        {
-          \tl_use:N \l__spath_prefix_tl
-          anonymous_\int_use:N \g__spath_anon_int
-          \tl_use:N \l__spath_suffix_tl
-        } {##1}
-        \clist_put_right:Nx #2 {anonymous_\int_use:N \g__spath_anon_int}
-        \int_gincr:N \g__spath_anon_int
+      \__tikzspath_check_path:nnn {
+        \__tikzspath_get_components:Nv #2
       }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
   get~ components~ of~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path:nn
     {
-      \clist_gclear_new:N #2
-      \spath_components_to_seq:Nv
-      \l__spath_tmpa_seq
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \seq_map_inline:Nn \l__spath_tmpa_seq
-      {
-        \tl_new:c
-        {
-          \tl_use:N \l__spath_prefix_tl
-          anonymous_\int_use:N \g__spath_anon_int
-          \tl_use:N \l__spath_suffix_tl
-        }
-        \tl_gset:cn
-        {
-          \tl_use:N \l__spath_prefix_tl
-          anonymous_\int_use:N \g__spath_anon_int
-          \tl_use:N \l__spath_suffix_tl
-        } {##1}
-        \clist_gput_right:Nx #2 {anonymous_\int_use:N \g__spath_anon_int}
-        \int_gincr:N \g__spath_anon_int
+      \__tikzspath_check_path:nnn {
+        \__tikzspath_gget_components:Nv #2
       }
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
   render~ components/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path:nn
     {
-      \group_begin:
-      \spath_components_to_seq:Nv
-      \l__spath_tmpa_seq
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
-      {
-        \spath_tikz_path:nn
-        {
-          every~ spath~ component/.try,
-          spath ~component~ ##1/.try,
-          spath ~component/.try={##1},
-          every~ #1~ component/.try,
-          #1 ~component~ ##1/.try,
-          #1 ~component/.try={##1},
-        }
-        {
-          ##2
-        }
+      \__tikzspath_check_path:nnn {
+        \__tikzspath_render_components:nv {#1}
       }
-      \group_end:
     }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    {#1}
+    {}
   },
   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}
+    \tl_if_head_is_group:nTF {#2}
     {
-      \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}
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_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}
-
-      \tl_if_empty:NTF \l__spath_tmpd_tl
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \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}}
-        }
+        \__tikzspath_insert_gaps_after_components:cVV
       }
-      {
-        \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
-            }
-          }
-        }
-      }
+    } {#1} { {} \l__tikzspath_tmpc_tl \l__tikzspath_tmpd_tl  }
+  },
+  insert~ gaps~ globally~ after~ components/.code~ 2~ args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_tl
+    }
 
-      \seq_clear:N \l__spath_tmpb_seq
-      \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \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 {\l__spath_tmpc_tl/2}
-        }
-        \seq_if_in:NnT \g__spath_tmpb_seq {##1}
-        {
-          \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
+        \__tikzspath_ginsert_gaps_after_components:cVV
       }
-      \tl_gset:Nx \g__spath_output_tl {\seq_use:Nn \l__spath_tmpb_seq {} }
-      \group_end:
-      \tl_set_eq:cN
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \g__spath_output_tl
-      \tl_gclear:N \g__spath_output_tl
+    } {#1} { {} \l__tikzspath_tmpc_tl \l__tikzspath_tmpd_tl  }
+  },
+  insert~ gaps~ after~ segments/.code~ 2~ args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
     }
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_tl
     }
-  },
-  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}
+
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \group_begin:
-      \tl_if_head_is_group:nTF {#2}
+      \__tikzspath_check_path:nnn
       {
-        \tl_set:Nx \l__spath_tmpc_tl { \tl_item:nn {#2} {1} }
-        \tl_set:Nx \l__spath_tmpd_tl { \tl_item:nn {#2} {2} }
+        \__tikzspath_insert_gaps_after_segments:cVV
       }
-      {
-        \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}
+    } {#1} { {} \l__tikzspath_tmpc_tl \l__tikzspath_tmpd_tl  }
+  },
+  insert~ gaps~ globally~ after~ segments/.code~ 2~ args={
+    \tl_if_head_is_group:nTF {#2}
+    {
+      \tl_set:Nx \l__tikzspath_tmpc_tl { \tl_item:nn {#2} {1} }
+      \tl_set:Nx \l__tikzspath_tmpd_tl { \tl_item:nn {#2} {2} }
+    }
+    {
+      \tl_set:Nn \l__tikzspath_tmpc_tl {#2}
+      \tl_clear:N \l__tikzspath_tmpd_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}
-
-      \tl_if_empty:NTF \l__spath_tmpd_tl
+    \__tikzspath_maybe_current_path_reuse:nnn
+    {
+      \__tikzspath_check_path:nnn
       {
-        \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}}
-        }
+        \__tikzspath_ginsert_gaps_after_segments:cVV
       }
-      {
-        \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
-            }
-          }
-        }
-      }
-
-      \seq_clear:N \l__spath_tmpb_seq
-      \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
-      {
-        \tl_set:Nn \l__spath_tmpa_tl {##2}
-        \seq_if_in:NnT \g__spath_tmpa_seq {##1}
-        {
-          \spath_shorten_at_end:Nn \l__spath_tmpa_tl {\l__spath_tmpc_tl/2}
-        }
-        \seq_if_in:NnT \g__spath_tmpb_seq {##1}
-        {
-          \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
-      }
-      \tl_gset:Nx \g__spath_output_tl {\seq_use:Nn \l__spath_tmpb_seq {} }
-      \group_end:
-      \tl_gset_eq:cN
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      \g__spath_output_tl
-      \tl_gclear:N \g__spath_output_tl
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} \l__tikzspath_tmpc_tl \l__tikzspath_tmpd_tl  }
   },
   join~ components/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g__spath_tmpa_seq
-      \foreach \l__spath_tmpa_tl in {#2}
+      \__tikzspath_check_path:nnn
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+        \__tikzspath_join_components:cn
       }
-      \seq_gsort:Nn \g__spath_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} > {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \seq_map_inline:Nn \g__spath_tmpa_seq
-      {
-        \spath_join_component:cn
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{##1}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
   join~ components~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g__spath_tmpa_seq
-      \foreach \l__spath_tmpa_tl in {#2}
+      \__tikzspath_check_path:nnn
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+        \__tikzspath_gjoin_components:cn
       }
-      \seq_gsort:Nn \g__spath_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} > {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \seq_map_inline:Nn \g__spath_tmpa_seq
-      {
-        \spath_gjoin_component:cn
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}{##1}
-      }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
   remove~ empty~ components/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_remove_empty_components:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_remove_empty_components:c
+      }
+    } {#1} { {} }
   },
   remove~ empty~ components~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \spath_gremove_empty_components:c
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_gremove_empty_components:c
+      }
+    } {#1} { {} }
   },
   replace~ lines/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \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 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_replace_lines:c
+      }
+    } {#1} { {} }
   },
   replace~ lines~ globally/.code={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \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 }
-    }
+      \__tikzspath_check_path:nnn
+      {
+        \spath_greplace_lines:c
+      }
+    } {#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}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g__spath_tmpa_seq
-      \foreach \l__spath_tmpa_tl in {#2}
+      \__tikzspath_check_path:nnn
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+        \__tikzspath_remove_components:cn
       }
-      \seq_gsort:Nn \g__spath_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} < {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \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_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpa_tl
-      {
-        \tl_clear:N \l__spath_tmpa_tl
-      }
-      \seq_clear:N \l__spath_tmpb_seq
-      \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
-      {
-        \tl_set:Nn \l__spath_tmpb_tl {##1}
-        \tl_if_eq:NNTF \l__spath_tmpb_tl \l__spath_tmpa_tl
-        {
-          \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpa_tl
-          {
-            \tl_clear:N \l__spath_tmpa_tl
-          }
-        }
-        {
-          \seq_put_right:Nn \l__spath_tmpb_seq {##2}
-        }
-      }
-      \tl_set:cx {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      {\seq_use:Nn \l__spath_tmpb_seq {} }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
   remove~ components~ globally/.code~ 2~ args={
-    \tl_if_exist:cTF
-    {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+    \__tikzspath_maybe_current_path_reuse:nnn
     {
-      \seq_gclear:N \g__spath_tmpa_seq
-      \foreach \l__spath_tmpa_tl in {#2}
+      \__tikzspath_check_path:nnn
       {
-        \seq_gput_right:NV \g__spath_tmpa_seq \l__spath_tmpa_tl
+        \__tikzspath_gremove_components:cn
       }
-      \seq_gsort:Nn \g__spath_tmpa_seq
-      {
-        \int_compare:nNnTF {##1} < {##2}
-        { \sort_return_same: }
-        { \sort_return_swapped: }
-      }
-      \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_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpa_tl
-      {
-        \tl_clear:N \l__spath_tmpa_tl
-      }
-      \seq_clear:N \l__spath_tmpb_seq
-      \seq_map_indexed_inline:Nn \l__spath_tmpa_seq
-      {
-        \tl_set:Nn \l__spath_tmpb_tl {##1}
-        \tl_if_eq:NNTF \l__spath_tmpb_tl \l__spath_tmpa_tl
-        {
-          \seq_gpop_left:NNF \g__spath_tmpa_seq \l__spath_tmpa_tl
-          {
-            \tl_clear:N \l__spath_tmpa_tl
-          }
-        }
-        {
-          \seq_put_right:Nn \l__spath_tmpb_seq {##2}
-        }
-      }
-      \tl_gset:cx {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      {\seq_use:Nn \l__spath_tmpb_seq {} }
-    }
-    {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-    }
+    } {#1} { {} {#2} }
   },
   draft~ mode/.is~ choice,
   draft~ mode/true/.code={
-    \bool_set_true:N \l__spath_draft_bool
+    \bool_set_true:N \l__tikzspath_draft_bool
   },
   draft~ mode/false/.code={
-    \bool_set_false:N \l__spath_draft_bool
+    \bool_set_false:N \l__tikzspath_draft_bool
   },
   maybe~ spot~ weld/.code={
-    \bool_if:NF \l__spath_draft_bool
+    \bool_if:NF \l__tikzspath_draft_bool
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_maybe_current_path_reuse:nnn
       {
-        \spath_spot_weld_components:c
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      }
+        \__tikzspath_check_path:nnn
+        {
+          \spath_spot_weld_components:c
+        }
+      } {#1} { {} }
     }
   },
   maybe~ spot~ weld~ globally/.code={
-    \bool_if:NF \l__spath_draft_bool
+    \bool_if:NF \l__tikzspath_draft_bool
     {
-      \tl_if_exist:cTF
-      {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
+      \__tikzspath_maybe_current_path_reuse:nnn
       {
-        \spath_spot_gweld_components:c
-        {\tl_use:N \l__spath_prefix_tl #1 \tl_use:N \l__spath_suffix_tl}
-      }
-      {
-        \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      }
+        \__tikzspath_check_path:nnn
+        {
+          \spath_spot_gweld_components:c
+        }
+      } {#1} { {} }
     }
   },
   transform~ to/.code~ 2~ args={
-    \group_begin:
-    \tl_if_exist:cTF
+    \__tikzspath_maybe_current_path:nn
     {
-      \tl_use:N \l__spath_prefix_tl
-      #1
-      \tl_use:N \l__spath_suffix_tl
-    }
-    {
-      \spath_reallength:Nv
-      \l__spath_tmpa_int
-      {
-        \tl_use:N \l__spath_prefix_tl
-        #1
-        \tl_use:N \l__spath_suffix_tl
+      \__tikzspath_check_path:nnn {
+        \__tikzspath_transform_to:nv {#2}
       }
-
-      \tl_set:Nx \l__spath_tmpb_tl
-      {\fp_to_decimal:n {(#2) * (\l__spath_tmpa_int)}}
-      \spath_transformation_at:NvV \l__spath_tmpc_tl
-      {
-        \tl_use:N \l__spath_prefix_tl
-        #1
-        \tl_use:N \l__spath_suffix_tl
-      }
-      \l__spath_tmpb_tl
-      \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpc_tl
     }
+    {#1}
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      \tl_gset_eq:NN \g__spath_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} }
+      \pgfsettransformentries {1}{0}{0}{1}{0pt}{0pt}
     }
-    \group_end:
-    \exp_last_unbraced:NV \pgfsettransformentries \g__spath_smuggle_tl
-    \tl_gclear:N \g__spath_smuggle_tl
   },
   upright~ transform~ to/.code~ 2~ args={
-    \group_begin:
-    \tl_if_exist:cTF
+    \__tikzspath_maybe_current_path:nn
     {
-      \tl_use:N \l__spath_prefix_tl
-      #1
-      \tl_use:N \l__spath_suffix_tl
-    }
-    {
-      \spath_reallength:Nv
-      \l__spath_tmpa_int
-      {
-        \tl_use:N \l__spath_prefix_tl
-        #1
-        \tl_use:N \l__spath_suffix_tl
+      \__tikzspath_check_path:nnn {
+        \__tikzspath_transform_upright_to:nv {#2}
       }
-
-      \tl_set:Nx \l__spath_tmpb_tl
-      {\fp_to_decimal:n {(#2) * (\l__spath_tmpa_int)}}
-      \spath_transformation_at:NvV \l__spath_tmpc_tl
-      {
-        \tl_use:N \l__spath_prefix_tl
-        #1
-        \tl_use:N \l__spath_suffix_tl
-      }
-      \l__spath_tmpb_tl
-      \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpc_tl
     }
+    {#1}
     {
-      \msg_warning:nnn { spath3 } { missing soft path } { #1 }
-      \tl_gset_eq:NN \g__spath_smuggle_tl { {1}{0}{0}{1}{0pt}{0pt} }
+      \pgfsettransformentries {1}{0}{0}{1}{0pt}{0pt}
     }
-    \fp_compare:nT { \tl_item:Nn \g__spath_smuggle_tl {4} < 0}
-    {
-      \tl_gset:Nx \g__spath_smuggle_tl
-      {
-        { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {1})} }
-        { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {2})} }
-        { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {3})} }
-        { \fp_eval:n { - (\tl_item:Nn \g__spath_smuggle_tl {4})} }
-        { \tl_item:Nn \g__spath_smuggle_tl {5} }
-        { \tl_item:Nn \g__spath_smuggle_tl {6} }
-      }
-    }
-    \group_end:
-    \exp_last_unbraced:NV \pgfsettransformentries \g__spath_smuggle_tl
-    \tl_gclear:N \g__spath_smuggle_tl
   },
   knot/.style~ n~ args={3}{
-    spath/split~ at~ self~ intersections=#1,
-    spath/remove~ empty~ components=#1,
-    spath/insert~ gaps~ after~ components={#1}{#2}{#3},
-    spath/maybe~ spot~ weld=#1,
-    spath/render~ components=#1
+    /tikz/spath/split~ at~ self~ intersections=#1,
+    /tikz/spath/remove~ empty~ components=#1,
+    /tikz/spath/insert~ gaps~ after~ components={#1}{#2}{#3},
+    /tikz/spath/maybe~ spot~ weld=#1,
+    /tikz/spath/render~ components=#1
   },
   global~ knot/.style~ n~ args={3}{
-    spath/split~ globally~ at~ self~ intersections=#1,
-    spath/remove~ empty~ components~ globally=#1,
-    spath/insert~ gaps~ globally ~after~ components={#1}{#2}{#3},
-    spath/maybe~ spot~ weld~ globally=#1,
-    spath/render~ components=#1
+    /tikz/spath/split~ globally~ at~ self~ intersections=#1,
+    /tikz/spath/remove~ empty~ components~ globally=#1,
+    /tikz/spath/insert~ gaps~ globally ~after~ components={#1}{#2}{#3},
+    /tikz/spath/maybe~ spot~ weld~ globally=#1,
+    /tikz/spath/render~ components=#1
   },
+  show/.default=current,
+  spot~ weld/.default=current,
+  spot~ weld~ globally/.default=current,
+  reverse/.default=current,
+  reverse~ globally/.default=current,
+  close/.default=current,
+  close~ globally/.default=current,
+  open/.default=current,
+  open~ globally/.default=current,
+  adjust~ and~ close/.default=current,
+  adjust~ and~ close~ globally/.default=current,
+  close~ with~ curve/.default=current,
+  close~ globally~ with~ curve/.default=current,
+  remove~ empty~ components/.default=current,
+  remove~ empty~ components~ globally/.default=current,
+  replace~ lines/.default=current,
+  replace~ lines~ globally/.default=current,
+  maybe~ spot~ weld/.default=current,
+  maybe~ spot~ weld~ globally/.default=current,
 }
-\tikzdeclarecoordinatesystem{spath}{%
+\cs_new_protected_nopar:Npn \__tikzspath_get_point_at:nn #1#2
+{
   \group_begin:
-  \tl_set:Nn \l__spath_tmpa_tl {#1}
-  \tl_trim_spaces:N \l__spath_tmpa_tl
+  \spath_reallength:Nn \l__tikzspath_tmpa_int {#2}
+  \tl_set:Nx \l__tikzspath_tmpb_tl
+  {\fp_to_decimal:n {(#1) * (\l__tikzspath_tmpa_int)}}
+  \spath_point_at:NnV \l__tikzspath_tmpc_tl {#2} \l__tikzspath_tmpb_tl
 
-  \seq_set_split:NnV \l__spath_tmpa_seq {~} \l__spath_tmpa_tl
-  \seq_pop_right:NN \l__spath_tmpa_seq \l__spath_tmpb_tl
+  \tl_clear:N \l__tikzspath_tmpd_tl
+  \tl_put_right:Nn \l__tikzspath_tmpd_tl {\pgf at x=}
+  \tl_put_right:Nx \l__tikzspath_tmpd_tl {\tl_item:Nn \l__tikzspath_tmpc_tl {1}}
+  \tl_put_right:Nn \l__tikzspath_tmpd_tl {\relax}
+  \tl_put_right:Nn \l__tikzspath_tmpd_tl {\pgf at y=}
+  \tl_put_right:Nx \l__tikzspath_tmpd_tl {\tl_item:Nn \l__tikzspath_tmpc_tl {2}}
+  \tl_put_right:Nn \l__tikzspath_tmpd_tl {\relax}
 
-  \tl_set:Nx \l__spath_tmpa_tl { \seq_use:Nn \l__spath_tmpa_seq {~} }
-  \tl_if_exist:cTF
-  {
-    \tl_use:N \l__spath_prefix_tl
-    \tl_use:N \l__spath_tmpa_tl
-    \tl_use:N \l__spath_suffix_tl
-  }
-  {
+  \tl_gset_eq:NN \g__tikzspath_output_tl \l__tikzspath_tmpd_tl
+  \group_end:
+ }
+\cs_generate_variant:Nn \__tikzspath_get_point_at:nn {VV, Vn, Vv}
 
-    \tl_set_eq:Nc
-    \l__spath_tmpa_tl
-    {
-      \tl_use:N \l__spath_prefix_tl
-      \tl_use:N \l__spath_tmpa_tl
-      \tl_use:N \l__spath_suffix_tl
-    }
+\tikzdeclarecoordinatesystem{spath}{%
+  \group_begin:
+  \tl_set:Nn \l__tikzspath_tmpa_tl {#1}
+  \tl_trim_spaces:N \l__tikzspath_tmpa_tl
 
-    \tl_if_empty:NTF \l__spath_tmpa_tl
-    {
-      \tl_gset_eq:NN \g__spath_smuggle_tl \pgfpointorigin
-    }
-    {
-      \spath_reallength:NV \l__spath_tmpa_int \l__spath_tmpa_tl
-      \tl_set:Nx \l__spath_tmpb_tl
-      {\fp_to_decimal:n {(\l__spath_tmpb_tl) * (\l__spath_tmpa_int)}}
-      \spath_point_at:NVV \l__spath_tmpc_tl \l__spath_tmpa_tl \l__spath_tmpb_tl
+  \seq_set_split:NnV \l__tikzspath_tmpa_seq {~} \l__tikzspath_tmpa_tl
+  \seq_pop_right:NN \l__tikzspath_tmpa_seq \l__tikzspath_tmpb_tl
 
-      \tl_clear:N \l__spath_tmpd_tl
-      \tl_put_right:Nn \l__spath_tmpd_tl {\pgf at x=}
-      \tl_put_right:Nx \l__spath_tmpd_tl {\tl_item:Nn \l__spath_tmpc_tl {1}}
-      \tl_put_right:Nn \l__spath_tmpd_tl {\relax}
-      \tl_put_right:Nn \l__spath_tmpd_tl {\pgf at y=}
-      \tl_put_right:Nx \l__spath_tmpd_tl {\tl_item:Nn \l__spath_tmpc_tl {2}}
-      \tl_put_right:Nn \l__spath_tmpd_tl {\relax}
-      \tl_gset_eq:NN \g__spath_smuggle_tl \l__spath_tmpd_tl
+  \tl_set:Nx \l__tikzspath_tmpa_tl { \seq_use:Nn \l__tikzspath_tmpa_seq {~} }
+
+  \__tikzspath_maybe_current_path:nV
+  {
+    \__tikzspath_check_path:nnn {
+      \__tikzspath_get_point_at:Vv \l__tikzspath_tmpb_tl
     }
   }
+  \l__tikzspath_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
+    \tl_gset_eq:NN \g__tikzspath_output_tl \pgfpointorigin
   }
+
   \group_end:
   \use:c {pgf at process}{%
-    \tl_use:N \g__spath_smuggle_tl
+    \tl_use:N \g__tikzspath_output_tl
     \pgftransforminvert
     \use:c {pgf at pos@transform at glob}
   }
+  \tl_gclear:N \g__tikzspath_output_tl
 }
 
 \ExplSyntaxOff

Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds	2022-10-26 19:57:44 UTC (rev 64817)
+++ trunk/Master/tlpkg/libexec/ctan2tds	2022-10-26 19:59:14 UTC (rev 64818)
@@ -3193,6 +3193,7 @@
  'silence'      => 'latex -translate-file=empty.tcx',   # no 8-bit
  'sillypage'	=> 'etex',
  'skdoc'        => 'tex',
+ 'spath3'	=> 'etex',
  'stix2-type1'	=> 'tex',
  'svg'		=> 'etex',
  'svn-multi'    => 'latex',  # interaction for .pl



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