4

I have a slightly different question from the already asked here on TeX.SE. I would like to define many paths inside a foreach statement and then use their names later on in the drawing.

When having one or few paths and no recursive code it is easy to use the save path and use path syntax as in the posted question. Sadly, when there are as many path as in the below MWE I cannot save them with save path=<recursive-path-name-expr>. Suppose e.g. I want to draw a certain number of arrows between two rectangles and then label someone of them by positioning a sloped node midway

\documentclass[tikz]{standalone}

\usetikzlibrary{positioning}
\newlength{\rectlong}
\setlength{\rectlong}{2cm}
\newlength{\rectshort}
\setlength{\rectshort}{1cm}

\begin{document}

\begin{tikzpicture}[mrect/.style={draw, minimum height=\rectlong, minimum width=\rectshort, rounded corners, outer sep=.1em}]
    \node[mrect, fill=blue] (r1) {};
    \node[right=of r1][mrect, fill=red] (r2) {};
    \foreach \x [count=\i] in {-0.9, -0.6, ..., 0.9} {
        \path[name=line\i] (r1) -- ([yshift={\x*\rectlong/2}] r2.west);
    }
    
\end{tikzpicture}

\end{document} 

Substituting \path with draw in the aforementioned code produce the following picture.

e.g.

Now suppose i want to put a sloped node after some piece of code on just selected line\i paths. I would like to have some command such as

\draw[use path=line5] node[scale=0.2, midway, sloped, above]{text along line};

to arrive to the following picture. A part from this specific example which can be achieved easily through other ways, is there a general way to reuse a path previously named with name=<path-name> without referring with a specific one with the save/use path syntax?

enter image description here

5
  • 1
    The main problem with foreach is that local definitions get lost. One would have to dig through the code to find the macro name actually used by TikZ for path names. Then you need a \global\let using \csname ...\endcsname and a whole lot of \expandafters. Jun 28, 2022 at 14:29
  • Frankly, it would be easier just to define the 7 lines separately, not using a loop. Jun 28, 2022 at 14:36
  • But maybe i want to draw 10 or more, i don't like much the "expand the code" approach when working with tikz, since it does not solve problems, just make a temporary solution...
    – GiuTeX
    Jun 28, 2022 at 15:51
  • The approach with the \endcsname could be a nice solution, but is seems a little bit crazy to me that i cannot use paths and define them recursively as i do with nodes, and always did on tikz with very useful results.
    – GiuTeX
    Jun 28, 2022 at 15:52
  • 1
    I stand corrected. Your code doesn't work even using \draw[name=line5] (r1) -- ([yshift={0.3*\rectlong/2}] r2.west); \draw[use path=line5] node[scale=0.2, midway, sloped, above]{text along line}; Jun 28, 2022 at 19:48

2 Answers 2

5

The spath3 library can handle this (development version is on github).

\documentclass{article}
%\url{https://tex.stackexchange.com/q/649216/86}
\usepackage{tikz}

\usetikzlibrary{positioning}
\usetikzlibrary{spath3}

\newlength{\rectlong}
\setlength{\rectlong}{2cm}
\newlength{\rectshort}
\setlength{\rectshort}{1cm}

\begin{document}

\begin{tikzpicture}[
  mrect/.style={
    draw,
    minimum height=\rectlong,
    minimum width=\rectshort,
    rounded corners,
    outer sep=.1em
  }
]
\node[mrect, fill=blue] (r1) {};
\node[right=of r1][mrect, fill=red] (r2) {};
\foreach \x [count=\i] in {-0.9, -0.6, ..., 0.9} {
  \path[spath/save global=line\i] (r1) -- ([yshift={\x*\rectlong/2}] r2.west);
}

\draw[spath/restore=line5,dashed] node[scale=.2, midway, sloped, above] {text along line};

\end{tikzpicture}

\end{document} 

It needs the global part of the spath/save global key because the assignment is happening inside a foreach loop which means that it is inside a TeX group. Further details are in the spath3 documentation.

Image with a reused path using the spath3 library

1
  • Thx for sharing this much useful library,
    – GiuTeX
    Jul 1, 2022 at 11:35
4

I see a couple of problems here; the first one I know how to solve, the second one I suspect is almost non-solvable.

The first problem is that the numbers can't be used, as-is, in macro names in LaTeX; so a macro like \line0 must be concocted in a difficult way. We can solve this using the package alphalph and converting 0, 1,... into a,b,c,...,aa,ab,.... Now you can compose the command to save the path.

The other problem is that it seems that you can reuse the path to stroke it, but not to add nodes to it --- I showed this using a plain saved path which does not work.

\documentclass[tikz, border = 2.78]{standalone}

\usetikzlibrary{positioning}
\newlength{\rectlong}
\setlength{\rectlong}{2cm}
\newlength{\rectshort}
\setlength{\rectshort}{1cm}
\usepackage{alphalph}

\begin{document}

\begin{tikzpicture}[mrect/.style={draw, minimum height=\rectlong, minimum width=\rectshort, rounded corners, outer sep=.1em}]
    \node[mrect, fill=blue] (r1) {};
    \node[right=of r1][mrect, fill=red] (r2) {};
    \path [save path=\lineA] (r1.north east) -- (r2.north west);
    \foreach \x [count=\i] in {-0.9, -0.6, ..., 0.9} {
        \edef\tmp{\noexpand\path [save path=\csname line\alphalph{\i}\endcsname]}
        \tmp (r1) -- ([yshift={\x*\rectlong/2}] r2.west);
    }
    % when using "use path" it seems that adding nodes is not working
    \draw [dashed, use path=\lineA]node[scale=0.2, midway, sloped, above]{text along line};

    % but the paths have been correctly saved in the loop
    \draw [use path=\linef] ;
    \draw [red, use path=\linee] ;

\end{tikzpicture}

\end{document} 

output of the code above

Another possibility is to save the start and end coordinates --- node names are much more flexible and easy to use (and global, even between different tikzpictures.)

\documentclass[tikz, border = 2.78]{standalone}

\usetikzlibrary{positioning}
\newlength{\rectlong}
\setlength{\rectlong}{2cm}
\newlength{\rectshort}
\setlength{\rectshort}{1cm}

\begin{document}

\begin{tikzpicture}[mrect/.style={draw, minimum height=\rectlong, minimum width=\rectshort, rounded corners, outer sep=.1em}]
    \node[mrect, fill=blue] (r1) {};
    \node[right=of r1][mrect, fill=red] (r2) {};
    \foreach \x [count=\i] in {-0.9, -0.6, ..., 0.9} {
        \path (r1) -- ([yshift={\x*\rectlong/2}] r2.west)
            coordinate[pos=0](start\i)
            coordinate[pos=1] (stop\i);
    }
    \draw [dashed] (start5) --
        node[scale=0.2, midway, sloped, above]{text along line} (stop5);

\end{tikzpicture}

\end{document}

output of the snippet above

0

You must log in to answer this question.

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