6

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}
12
  • If I add \draw (0,0)--(1,1) I get the same error both with pdflatex and latex
    – egreg
    Dec 18, 2013 at 18:13
  • @egreg Upon closer examination, I see that I also get the pdflatex error, but the compilation goes through and the image is rendered. Dec 18, 2013 at 18:36
  • Please make the example into one that produces an error.
    – egreg
    Dec 18, 2013 at 18:42
  • I do not get any error with a \draw (0,0)--(1,1); afetr end{scope}. Current TL2013. It looks like that you used \x after the scope end
    – user2478
    Dec 18, 2013 at 18:49
  • @Herbert What is TL2013? I definitely did not use \x after \end{scope}. Dec 18, 2013 at 19:12

1 Answer 1

7

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:

\def\tikz@intersect@finish{%    
        \ifx\tikz@intersect@namedpaths\pgfutil@empty%
        \else%
                \tikz@intersect@namedpaths%
                \let\tikz@intersect@namedpaths=\pgfutil@empty%
        \fi%
}

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 the scope 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 name line \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) as line \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 that line \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:

\makeatletter
\def\tikz@intersect@finish{%    
        \ifx\tikz@intersect@namedpaths\pgfutil@empty%
        \else%
                \tikz@intersect@namedpaths%
                \global\let\tikz@intersect@namedpaths=\pgfutil@empty%
        \fi%
}
\makeatother

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.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/150598/86}
\usepackage{tikz} 
\usetikzlibrary{intersections}

\begin{document}

\begin{tikzpicture}
\draw[name path=abc] (-3,-3) -- (3,3);
\draw[name path=def] (3,-3) -- (-3,3);
\draw[green, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=6pt];
\begin{scope}
\draw[name path=abc] (-3,-2) -- (2,3);
\draw[green, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=6pt];
\end{scope}
\path (0,0); % needed to invoke \tikz@intersect@namedpath from inside the scope
\draw[blue, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=10pt];
\end{tikzpicture}

\makeatletter
\def\tikz@intersect@finish{%    
        \ifx\tikz@intersect@namedpaths\pgfutil@empty%
        \else%
                \tikz@intersect@namedpaths%
                \global\let\tikz@intersect@namedpaths=\pgfutil@empty%
        \fi%
}
\makeatother

\begin{tikzpicture}
\draw[name path=abc] (-3,-3) -- (3,3);
\draw[name path=def] (3,-3) -- (-3,3);
\draw[green, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=6pt];
\begin{scope}
\draw[name path=abc] (-3,-2) -- (2,3);
\draw[green, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=6pt];
\end{scope}
\path (0,0); % needed to invoke \tikz@intersect@namedpath from inside the scope
\draw[blue, ultra thick, name intersections={of=abc and def}] (intersection-1) circle[radius=10pt];
\end{tikzpicture}
\end{document}

Intersection bug

3
  • 2
    I've reported this on the PGF bug tracker: sourceforge.net/p/pgf/bugs/285 Dec 19, 2013 at 8:24
  • Thank you, Andrew, for your definitive and well-expressed solution to the problem - I'm duly awed by your grasp of the underlying mechanics. It is appreciated. Dec 19, 2013 at 8:59
  • @steven_nevets It's actually close to something I'd come across before (I think for tex.stackexchange.com/a/21426/86) so it didn't actually take all that much detective work! Dec 19, 2013 at 10:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .