The following code compiles in both DVI and PDF format. However, if I draw anything after the \end{scope}
command, it won't compile in DVI, and I get the following error message:
Latex> ! Undefined control sequence.
Latex> \tikz@intersect@namedpaths ...t@path@name@line \x
\endcsname {\pgfsyssoftpat...
The PDF registers the same error but the compilation goes through and the image is rendered. What is causing this error? I have so much more to add to this figure!
UPDATE: As requested, I've added a random draw command \draw (0,0) circle [radius=1cm];
which then triggers the error. Using path name global=line \x
does not solve the problem.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections,backgrounds}
\begin{document}
\begin{tikzpicture}
%axis
\draw (-.5,0) -- (6.5,0);
%curve
\draw[yshift=1cm,name path=curve] (-.5,0) %vertically shiftable
to[out=70,in=180] (.7,1.5)
to[out=0,in=180] (2,.5)
to[out=0,in=180] (4.5,2.5)
to[out=0,in=160] (6.5,1);
%rectangles
\begin{scope}[on background layer]
\foreach \x in {0,1,2,5}{
\path[name path=line \x] (\x,0) -- (\x,4);
\path[name intersections={of=curve and line \x, by={isect \x}}];
\draw[fill=gray!50] (isect \x) rectangle (\x+1,0);
\draw[fill] (isect \x) circle [radius=2pt];
}
\end{scope}
\draw (0,0) circle [radius=1cm]; % Won't compile with this added draw
\end{tikzpicture}
\end{document}
Best Answer
This is, I think, a bug in the
intersections
library in TikZ. Although it does not produce an error with the CVS version of TikZ, the underlying bug is still there.When TikZ names a path then it has to save that path to a macro. Because the path might undergo considerable changes as it is being processed, the best time to save it is right at the end. So the intersection library hooks in to the macro
\tikz@finish
which is called last of all. So it stores up all the necessary intersection code into a macro,\tikz@intersect@namedpaths
, which it then executes right at the end. The addition of code looks like this:This is hooked into
\tikz@finish
to run after all the other stuff.The problem with this is that
\let
. The macro\tikz@intersect@namedpaths
is defined globally. This is because inside a path then there can be all manner of groupings involved and TikZ doesn't want to have to bother with them. So it defines this globally. However, it only clears it locally. Normally, this is alright because the clearing happens at the same level as the\path
command. In this situation, though, that is inside thescope
meaning that when the scope ends then\tikz@intersect@namedpaths
is restored to its previous global value. This is the value it had during the\path[name path=line \x] (\x,0) -- (\x,4);
when it saved the path with nameline \x
. So when the\draw
command after the scope is executed,\tikz@intersect@namedpaths
is not empty and so is processed.This is definitely a bug, because it means that any paths named inside the scope are now available outside it - so if you use the same path name before the scope and inside it then the path after the scope is the one defined inside, not the previous one.
The reason for the complaint in the code is that in an earlier version of TikZ then the macro
\tikz@intersect@namedpaths
had the path names stored as they were specified. So it stored the path name (in your example) asline \x
. This means that when\tikz@intersect@namedpaths
is executed in the\draw
command outside the scope, it tries to figure out the meaning of\x
and fails, because it is no longer defined. Later versions of TikZ expand the path name first, meaning thatline \x
is stored as, for example,line 1
. This is why there is no longer an error produced with later versions of TikZ, or when the path name is expanded before it is passed in to the code (this is what the.expanded
does). However, the underlying bug is still present and still detectable by looking at what paths are saved.The real fix is to make the reset of
\tikz@intersect@namedpaths
into a global reset. This is simple enough: prepend\global
to that\let
. Thus the correct solution is to add the following to your preamble:Here's an example showing the persistence of paths. The key is the blue circle. This ought to be at the intersection of the lower path, but due to using the same name inside the scope, it gets shifted to the upper path (after one extra path command since we need
\tikz@intersect@namedpaths
to be processed). Redefining\tikz@intersect@finish
as I describe fixes this.