pgf-tikz / pgf

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

\foreach behavior inside a \draw #1303

Open alceu-frigeri opened 5 months ago

alceu-frigeri commented 5 months ago

Brief outline of the bug

Hi, I don't know if it qualifies as a bug, or a misunderstanding of mine about how a foreach should work, when used inside a path. From my understanding, section 88 of the manual (pages 1001+), the foreach should just, mainly, expands the code inside the braces (if there is one, replacing the variables of the foreach). In the example below, my understanding was that the 3 cases (commented out) should be equivalent. producing a line from (X) to node (nA) node (nB) and finally coordinate (X). case (1), the simplest, does just that, connecting the arcs (at node nA and node nB) as expected. case (2), 'does the job', by means of three \draw commands \draw (X) -- (nA) ; \draw (nA) -- (nB); \draw (nB) -- (X)

case (3) was the surprise for me, I expected it to be equivalent too (well, to be equal to case (1)) .. but I got a continuous line from (X) to (Y) ignoring the nodes (arcs) dimensions.

Is that the expected behavior? what am I missing on it? or is it a foreach miss behavior ?

For a better context: I'm using this construct with coordinates obtained from \draw[name intersections={of=... (intersections library). So I'm forced to use foreach statements to connect the many 'intersection' coordinates, in which I place an arc node in each intersection.

In my use case what I have implemented, for now, is a workaround based on case (2), better said, from the intersection coordinate/nodes list I generate a clist of node-pairs then I execute a final foreach with said list.

 \gdef\@tmpA{#3}
  \gdef\@ListA{}
  \foreach \x in {1,...,\csuse{#2T}} {\xappto{\@ListA}{\@tmpA/n#2-\x,}\xdef\@tmpA{n#2-\x}}
  \xappto{\@ListA}{n#2-\csuse{#2T}/#4}
  \foreach \xa/\xb in \@ListA {\draw[line cap=round] (\xa) -- (\xb);}

(that's just to have an idea what I ended doing, #3would be X, #4 would be Y, #2T is the macro name with the number of intersections.. the n#2-\x are the intersection node names. It works, just fine, but it would be nicer not to have to use such a construct to just connect the nodes, and be able, for instance, to have something like

\draw (#3) \foreach \x in {1,...,\csuse{#2T}} { -- (\x) } -- (#4) ;

Minimal working example (MWE)

\documentclass{article}
\usepackage{tikz}

%%% This is just to make the page tight... not needed for the MWE
%\usepackage[active,tightpage]{preview}
%\PreviewEnvironment{tikzpicture}
%\setlength\PreviewBorder{5pt}%

\begin{document}

\begin{tikzpicture}
  \path 
    (0,0) coordinate(X) 
    (1,1) coordinate(A) node[minimum size=4.3pt,inner sep=0pt](nA){}
    (2,2) coordinate(B) node[minimum size=4.3pt,inner sep=0pt](nB){}
    (3,3) coordinate(Y)
    ;
  \draw[rotate=45] 
    (A) +(-7pt/2,0) arc[start angle=180,end angle=0,radius=7pt/2]
    (B) +(-7pt/2,0) arc[start angle=180,end angle=0,radius=7pt/2]
    ;

    % Case (1)
  %\draw (X) -- (nA) -- (nB) -- (Y) ;

    % Case (2)
  %\foreach \x/\y in {X/nA,nA/nB,nB/Y} {\draw (\x) -- (\y);}

    % Case (3)
  %\draw (X) \foreach \x in {nA,nB,Y} { -- (\x)};

\end{tikzpicture}

\end{document}
loopspace commented 5 months ago

The issue appears to be that the \tikz@moveto@waiting is not part of the suite that TikZ remembers from one iterate of a foreach to the next. More details, and a suggested fix, can be found at https://tex.stackexchange.com/a/706676/86

(Once I've updated my local version of PGF then I can create a pull request for this, but I've only tested it with the broken code so haven't verified that it doesn't break anything else.)

alceu-frigeri commented 5 months ago

Thanks again for your reply. A note, though, a just took a second look on an example from the manual, page 1003.

\tikz
\draw (0,0)
foreach \x in {1,...,3} { -- (\x,1) -- (\x,0) };

Which works as one would expect, I mean, connecting (0,0) -- (1,1) -- (1,0) -- (2,1) -- (2,0) -- (3,1) -- (3,). I mean, the (miss) behavior was due the using of nodes, and not coordinates.

muzimuzhi commented 5 months ago

The issue appears to be that the \tikz@moveto@waiting is not part of the suite that TikZ remembers from one iterate of a foreach to the next.

Similar: #1047, in which \tikz@tagent was found to be not remembered by foreach path operation.

loopspace commented 5 months ago

I've refactored my fix to make it more extendible, and included \tikz@tangent and \tikztostart in the list.