pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.15k stars 108 forks source link

name intersections with sort-by inside \foreach loop produced wrong intersection as first one #1345

Open robert-g-liu opened 4 months ago

robert-g-liu commented 4 months ago

Brief outline of the bug

In below MWE three different coding styles were given for enabling sort-by option in name intersections. The first one didn't work. Not sure why name path {Ray \i} (or {Ray\i}, {Ray-\i}) wasn't accepted in inside a \foreach loop.

BTW, the second code snippet worked though it's sort of bad idea to share the same name path between all rays.

Minimal working example (MWE)

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{document}
\begin{tikzpicture}[scale=2]

    \draw [name path=Circle] (5,0) circle (2);

    % what'wrong with using {Ray \i}?
    \foreach \i in {1} {
         \draw [thick, name path={Ray \i}] (0, 0) -- (7,2);
         \draw [fill=red, name intersections={of = {Ray \i} and Circle, name=c, sort by={Ray \i}}]
              (c-1) circle (1mm);
    }

    \foreach \i in {1,2} {
         \draw [blue, name path=Ray] (0, 0) -- (7,{0.2*\i+1.3});
         \draw [fill,name intersections={of = Ray and Circle, name=c, sort by=Ray}]
              (c-1) circle (0.5mm);
    }

    \draw [name path=Ray X] (0, 0) -- (7,2.5);
    \draw [fill,name intersections={of =  Ray X and Circle, name=c, sort by=Ray X}]
         (c-1) circle (0.5mm);
\end{tikzpicture}
\end{document}
Qrrbrbirlbel commented 4 months ago

BTW, the second code snippet worked though it's sort of bad idea to share the same name path between all rays.

In this case, it doesn't really matter because the path is only available for that iteration of the loop.

But that's no excuse for the apparent bug.


The problem comes from expansion. For the of key, the path names do not get fully expanded: https://github.com/pgf-tikz/pgf/blob/44f8137449b34f62bc6371bd442ae5cc98f60f18/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex#L138-L141 while for the sort by key ithe given argument gets expanded: https://github.com/pgf-tikz/pgf/blob/44f8137449b34f62bc6371bd442ae5cc98f60f18/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryintersections.code.tex#L123

The code compares a macro that expands to Ray 1 with a macro that expands to \Ray \i and the sorting will fall back to no sorting.

So, as a workaround, you can do of/.expanded = {Ray \i} and Circle or we fix the of key:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{intersections}
\makeatletter
\tikzset{
  intersection/of/.code args={#1 and #2}{%
    \edef\tikz@intersect@path@a{#1}%
    \edef\tikz@intersect@path@b{#2}}}
\makeatother
\begin{document}
\begin{tikzpicture}[scale=2]
\draw [name path=Circle] (5,0) circle (2);
\foreach \i in {1} {
  \draw [thick, name path={Ray \i}] (0, 0) -- (7,2);
  \draw [fill=red, name intersections={of = {Ray \i} and Circle, name=c, sort by={Ray \i}}]
    (c-1) circle (1mm);
}
\end{tikzpicture}
\end{document}