8

I'd like very much to define a foreach loop that looks like this:

\foreach \pointA-\pointB in {(1,0)-(2,2),(3,4)-(2,1)}{
    \draw \pointA -- \pointB
}

so that for each couple of points the lines between them would get drawn.

Can I get \foreach to accept this kind of input? Or is there another way to do this? I'm going to define a macro to quickly draw lines between couples of points.

I know I could use / instead of - but then I would also have to wrap the coordinates in { }, which is a lot of work.

romeovs
  • 9,102
  • 2
    You can cut the "a lot of work" into a half via going in the wrong direction such as \foreach \x in {{(1,0)--(2,2)},{(3,4)--(2,1)}}{\draw \x;}. This requires 1 pair of braces per two coordinates, but hey, improvement is improvement! :) – percusse Oct 27 '11 at 23:59

2 Answers2

8

You can use / instead of -. You also need to wrap the coordinates in {} (see the comments on this answer by Martin if you wish to know why), then your example would become:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \pointA/\pointB in {{(1,0)}/{(2,2)},{(3,4)}/{(2,1)}}{
  \draw \pointA -- \pointB;
}
\end{tikzpicture}
\end{document}

This can also be extended to more than 2 elements, just add another / \pointC. All of this is treated on page 506 of the Tikz manual.

EDIT Ok, after your edit (better to specify that, otherwise Peter and I look silly ;)), my answer isn't all that great anymore. Basically you can't do what you want due to the same reasons as in the comment I referenced above. You can work around it though. Note: this is just something hacked together quickly, it probably doesn't handle everything great, but it handles your MWE and can probably be extended.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcounter{n}
\makeatletter
\def\wrap(#1)#2{%
    \stepcounter{n}%
    \coordinate (\number\value{n}) at (#1);%
    \if#2(%
        \wraprest#2%
    \else\fi%
}
\def\wraprest(#1)#2{%
    \stepcounter{n}%
    \coordinate (\number\value{n}) at (#1);%
    \if#2(% 
        \wrap#2%
    \else\fi%
}
\begin{document}
\begin{tikzpicture}
\wrap(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)(7,0)(8,0)x%
\foreach \pointA in {1,3,...,\number\value{n}}{
    \pgfmathsetmacro{\pointB}{\pointA+1}
  \draw (\pointA) -- (\pointB);
}
\end{tikzpicture}
\makeatother
\end{document}

This uses Peter's method of defining coordinates and using those in the list. First a coordinate is created for each (x,y) and these are numbered, such that lines go from n to n+1 where n is odd. If you want delimiters between pairs those can be added with a slight modification. (The x at the end of the wrap can be anything, just not ().

Roelof Spijker
  • 17,663
  • 5
  • 55
  • 63
6

You can, but you would have to wrap each coordinate in a {} since the \foreach uses the , to separate args:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \pointA/\pointB in {{(1,0)}/{(2,2)},{(3,4)}/{(2,1)}}{
    \draw \pointA -- \pointB;
}
\end{tikzpicture}
\end{document}

However, I normally tend to define the coordinate first with names, and use:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (1,0);
\coordinate (B) at (2,2);
\coordinate (C) at (3,4);
\coordinate (D) at (2,1);

\foreach \pointA/\pointB in {A/B, C/D}{
    \draw (\pointA) -- (\pointB);
}
\end{tikzpicture}
\end{document}
Peter Grill
  • 223,288