Menu

#285 [intersections] \tikz@intersect@namedpaths persists outside scopes

TeX Live 2019
closed-fixed
nobody
5
2019-01-24
2013-12-19
No

In the intersections library, the macro \tikz@intersect@namedpaths is used to ensure that the path-saving is done right at the end. It is globally defined, but is only locally reset to empty when it has been processed. This means that, for example, it can persist outside scopes meaning that paths named inside a scope can become available outside it, causing potential issues with conflicting names.

The fix would seem to be to make the reset global by prefixing the \let inside \tikz@intersect@finish by \global.

Here's a MWE. See also this question on TeX-SX.

\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}

Discussion

  • Till Tantau

    Till Tantau - 2014-03-20
    • status: open --> closed-fixed
     
  • Till Tantau

    Till Tantau - 2014-03-20

    Fixed in CVS as suggested.

     
  • Christian Feuersänger

    The bugfix broke the manual, in particular, the euclid example

    \documentclass{standalone}
    
    \usepackage{tikz}
    \usetikzlibrary{intersections,calc,through}
    
    \begin{document}
    \pgfdeclarelayer{background}
    
    \begin{tikzpicture}
      \coordinate [label=left:$A$]  (A) at (0,0);
      \coordinate [label=right:$B$] (B) at (1.25,0.25);
      \draw (A) -- (B);
    
      \node (D) [name path=D,draw,circle through=(B),label=left:$D$]  at (A) {};
      \node (E) [name path=E,draw,circle through=(A),label=right:$E$] at (B) {};
    
      % Name the coordinates, but do not draw anything:
      \path [name intersections={of=D and E}];
    
      \coordinate [label=above:$C$] (C) at (intersection-1);
    
      \draw [red] (A) -- (C);
      \draw [red] (B) -- (C);
    \end{tikzpicture}
    \end{document}
    

    It fails with

    ! Package tikz Error: I do not know the path named `D'. Perhaps you misspelt it.

    Reverting the patch makes this work again.

    I would suggest to move the clearing instruction either to \end{scope} or to \end{tikzpicture}, whatever fits best... does that make sense?

    I will reopen the ticket.

    @Till if you do not mind, I will revert the fix for now such that the manual compiles

     

    Last edit: Stefan Pinnow 2018-12-21
  • Christian Feuersänger

    • status: closed-fixed --> open
     
  • Henri Menke

    Henri Menke - 2018-12-24

    Not easily fixable, see note in the code in \tikz@intersect@finish.

     
  • Kpym

    Kpym - 2019-01-06

    I was thinking to reset \tikz@intersect@namedpaths using \aftergroup. In the folowing example it works

    \documentclass[tikz,border=7pt]{standalone}
    \usetikzlibrary{intersections}
    \makeatletter
    \def\tikz@intersect@finish{%
      \ifx\tikz@intersect@namedpaths\pgfutil@empty%
      \else%
        \tikz@intersect@namedpaths%
        \gdef\temp{\let\tikz@intersect@namedpaths=\pgfutil@empty}%
        \aftergroup\temp%
      \fi%
    }%
    
    \begin{document}
      \begin{tikzpicture}
        \draw[help lines] (0,0) grid +(3,3);
        \draw[name path=a] (0, 1) -- +(3, 0) node[right,pos=1,sloped]{path a (outside)};
        \draw[name path=b] (1, 0) -- +(0, 3) node[right,pos=1,sloped]{path b (outside)};
        {
          {
            \draw[name path=a] (0, 2) -- +(3, 0) node[right,pos=1,sloped]{path a (inside)};
          }
          \draw[name path=b] (2, 0) -- +(0, 3)  node[right,pos=1,sloped]{path b (inside)};;
        }
        \path;% execute \tikz@intersect@namedpaths
    
        \fill[name intersections={of=a and b},red] (intersection-1) circle (2pt) node[below left]{outside};
      \end{tikzpicture}
    \end{document}
    

    the same code without the fix produce

    and it do not breake the code from the manual given by Christian Feuersänger earlier.

    But it is not working if we have multiple groups like this

    \documentclass[tikz,border=7pt]{standalone}
    \usetikzlibrary{intersections}
    \makeatletter
    \def\tikz@intersect@finish{%
      \ifx\tikz@intersect@namedpaths\pgfutil@empty%
      \else%
        \tikz@intersect@namedpaths%
        \gdef\temp{\let\tikz@intersect@namedpaths=\pgfutil@empty}%
        \aftergroup\temp%
      \fi%
    }%
    
    \begin{document}
      \begin{tikzpicture}
        \draw[help lines] (0,0) grid +(3,3);
        \draw[name path=a] (0, 1) -- +(3, 0) node[right,pos=1,sloped]{path a (outside)};
        \draw[name path=b] (1, 0) -- +(0, 3) node[right,pos=1,sloped]{path b (outside)};
        {{
          {{
            \draw[name path=a] (0, 2) -- +(3, 0) node[right,pos=1,sloped]{path a (inside)};
          }}
          \draw[name path=b] (2, 0) -- +(0, 3)  node[right,pos=1,sloped]{path b (inside)};;
        }}
        \path;% execute \tikz@intersect@namedpaths
    
        \fill[name intersections={of=a and b},red] (intersection-1) circle (2pt) node[below left]{outside};
      \end{tikzpicture}
    \end{document}
    

    So this is not a good fix, but it is clear that \tikz@intersect@namedpaths should not be available outside the current group.

     
  • Kpym

    Kpym - 2019-01-06

    One more : I think that \global\let\tikz@intersect@namedpaths=\pgfutil@empty (with \gloabl !) should be executed rally "after" the ; if this is possible. The \tikz@finish is executed more than once for some "complex" paths, end this is why \gloabl breaks some examples.
    For example the following code, where I aded manually \clear@namedpaths after each ;, works fine.

    \documentclass[tikz,border=7pt]{standalone}
    \usetikzlibrary{intersections}
    \makeatletter
    \def\clear@namedpaths{\global\let\tikz@intersect@namedpaths=\pgfutil@empty}
    \begin{document}
      \begin{tikzpicture}
        \draw[help lines] (0,0) grid +(3,3); \clear@namedpaths
        \draw[name path=a] (0, 1) -- +(3, 0) node[right,pos=1,sloped]{path a (outside)}; \clear@namedpaths
        \draw[name path=b] (1, 0) -- +(0, 3) node[right,pos=1,sloped]{path b (outside)}; \clear@namedpaths
        {{
          {{
            \draw[name path=a] (0, 2) -- +(3, 0) node[right,pos=1,sloped]{path a (inside)}; \clear@namedpaths
          }}
          \draw[name path=b] (2, 0) -- +(0, 3)  node[right,pos=1,sloped]{path b (inside)}; \clear@namedpaths
        }}
        \path; \clear@namedpaths % execute \tikz@intersect@namedpaths
    
        \fill[name intersections={of=a and b},red] (intersection-1) circle (2pt) node[below left]{outside}; \clear@namedpaths
      \end{tikzpicture}
    \end{document}
    

    And this manual cleaning looks to be backward compatible. But I don't know if there is a possibility in tikz to run something really after the ; (something like execute after path end key).

     
  • Kpym

    Kpym - 2019-01-07

    I think I have found a solution (or an idea of solution): instead of resetting globally \tikz@intersect@namedpaths after the ; we can do it at the beginning of every \path command. Here is the code :

    \let\tikz@installcommands@original\tikz@installcommands%
    \def\tikz@installcommands{%
      \tikz@installcommands@original%
      \let\path@original\path%
      \def\path{%
        \global\let\tikz@intersect@namedpaths=\pgfutil@empty% clear \tikz@intersect@namedpaths globally
        \path@original%
      }
    }
    

    And if this code is used we don't need to clear \tikz@intersect@namedpaths in \tikz@intersect@finish

    \def\tikz@intersect@finish{%
      \tikz@intersect@namedpaths%
    }
    

    or we can simply remove \tikz@intersect@finish and replace it with \tikz@intersect@namedpaths inside \tikz@finish.

    This works with the examples I have tested.

     

    Last edit: Kpym 2019-01-07
  • Henri Menke

    Henri Menke - 2019-01-10

    Does it also work in low-level PGF or does the problem not exist there?

     
    • Kpym

      Kpym - 2019-01-10

      This is a problem at TikZ level only, conserning name path key (vs name path global key).

       

      Last edit: Kpym 2019-01-10
      • Henri Menke

        Henri Menke - 2019-01-23

        Could you please submit a merge request with the required changes?

         
        • Kpym

          Kpym - 2019-01-23

          Done.

           
  • Henri Menke

    Henri Menke - 2019-01-24
    • status: open --> closed-fixed
     
  • Henri Menke

    Henri Menke - 2019-01-24
    • Group: v1.0 (example) --> TeX Live 2019