# Saving and reusing/combining paths in TikZ?

In a package using TikZ, I'm generating two paths (depending on some option values), which I now need to combine to one path that should be used for \filldraw. I found Programming in TikZ which really lets me save and restore a path. However, anything I do after the restore does not have any effect on the \filldraw. In particular, in the example the -- cycle is completely ignored.

Any idea how to save one or two paths in TikZ and then restore and continue or even concatenate two paths?

A simplified example is:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\makeatletter

\begin{tikzpicture}
\path[save path=\tmppath] (0,0) -- (2,2) -- (4,1);
\path[save path=\tmppathII] (6,-2) -- (3,-2);

% Effectively, I want the following, but by using \tmppath and \tmppathII:
% \filldraw[color=red,fill=blue] (0,0) -- (2,2) -- (4,1) -- (6,-2) -- (3,-2) -- cycle;

% This properly draws/fills the \tmppath, but does NOT use the -- cycle at all...
\pgfsyssoftpath@setcurrentpath{\tmppath} -- cycle \filldraw[color=red,fill=blue];

% This only draws \tmppathII, not the whole constructed path...
% \pgfsyssoftpath@setcurrentpath{\tmppath} --
% \pgfsyssoftpath@setcurrentpath{\tmppathII} -- cycle \filldraw[color=red,fill=blue];

\end{tikzpicture}
\end{document}

-

Your first case almost works. Where it needs tweaking is that the -- cycle syntax needs to be given to the \filldraw command. The second needs a little more work to get it to ... er ... work.

You probably already know this (since you've discovered the soft paths), but I'll explain the mechanics anyway just in case anyone else is listening in. When you give a TikZ command, like \path (0,0) -- (2,2) -- (4,1); then TikZ translates that in to the underlying PGF commands, which are then used to build a soft path. A soft path is held in a macro (or a series of macros) and is the basic instructions on how the path is built. It is "soft" in that it can still be manipulated, but it is in a very simple format (which makes the manipulation much simpler). When the save path key is given then TeX saves the current soft path. When TikZ/PGF are working on a path then there is a "current soft path" which is the one that they are using right at this moment. Any commands that define a path are added to this one. The sneaky bit is that TikZ does not blank the current soft path when it starts, so when a command such as \draw starts up then it simply appends its stuff to whatever was there already. This is usually the empty path because whenever a path is used (ie rendered) then the current soft path is set to "empty". But it needn't be.

So the command \pgfsyssoftpath@setcurrentpath{\tmppath} is essentially saying to the next TikZ command (the \filldraw) "instead of starting with a blank path, start with \tmppath". But the extension commands have to go through the TikZ system to be processed in to soft path tokens, which is why the -- cycle has to be on the \filldraw instead of after the \pgfsyssoftpath@setcurrentpath.

Now we see why the second doesn't work. The first says "Use \tmppath" and the second says, "No, use \tmppathII". So the second wins and we just get the second path. In this case you want to concatenate the paths. If you really just wanted to concatenate them then you could just put one after the other (this needs a little care with expansions, but is perfectly possible). Assuming that \ge@addto@macro is defined to add the expansion of the second macro to the end of the first then you would do:

\ge@addto@macro\tmppath\tmppathII
\pgfsyssoftpath@setcurrentpath{\tmppath}
\filldraw[color=red,fill=blue] -- cycle;


Where it gets complicated is that you want to join them with a lineto not a moveto. Every soft path starts with an explicit move. You need to swap that for a line. To do this, we need to gobble up the first token of \tmppathII (which is a \pgfsyssoftpath@movetotoken) and put \pgfsyssoftpath@linetotoken in its place.

At this point, I would start thinking, "Wouldn't it be nice if there was a package that did all this for me?". Fortunately, I thought that a while ago and as there wasn't one, wrote it. I've just updated it to do the concatenate with lineto that is needed.

So go to the TeX-SX Package, download the file spath.dtx, run pdflatex spath.dtx, then the following will do what you want:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{spath}
\begin{document}
\begin{tikzpicture}
\path[save path=\tmppath] (0,0) -- (2,2) -- (4,1);
\pgfoonew \patha=new spath(\tmppath)
\path[save path=\tmppath] (6,-2) -- (3,-2);
\pgfoonew \pathb=new spath(\tmppath)
\patha.concatenate with lineto(,\pathb)
\patha.close()
\patha.use path with tikz(line width=3pt,draw=red,fill=blue)
\end{tikzpicture}
\end{document}


(Edit: Got bored and implemented the close method. The line width=3pt is to show that the path really does get closed.)

Result:

-
Wow, thanks for all the insider information! –  Reinhold Kainhofer Aug 27 '11 at 18:43
@Reinhold: No worries! If the spath package is overkill, this particular case wouldn't be difficult to implement by individual macros. –  Loop Space Aug 27 '11 at 18:46
Actually, I found an even simpler solution: Not going through pgf pathes at all, but simply creating the parts using ordinary tex macros and then inserting them directly into the \filldraw. So the pgf pathes would only be created directly for the \filldraw. Unfortunately, I can't answer my question yet (8 hours before I can answer my own question), but I'll submit that solution when SE allows me. –  Reinhold Kainhofer Aug 27 '11 at 18:51
@Reinhold: Yes, that's definitely simpler! I saw the use of soft paths and reacted accordingly so the simpler method never crossed my mind. –  Loop Space Aug 27 '11 at 18:55

Actually, I just realized that there is no need to let TikZ/PGF create pathes in the first place. One solution is to simply store the text needed to generate the pathes in a tex command, which you then simply insert (i.e. expand) into the \path. Here's a simple example:

\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\newcommand{\aaa}{(0,0) -- (2,2) -- (4,1)}
\newcommand{\bbb}{(6,-2) -- (3,-2)}

\filldraw[color=red,fill=blue] \aaa -- \bbb -- cycle;

\end{tikzpicture}
\end{document}

-