2

I want to automate drawing a simple picture with TikZ using \foreach; I wrote the following code (output below):

\documentclass[tikz, border=1mm]{standalone}
\begin{document}
\begin{tikzpicture}
  \tikzstyle{every node}=[circle, inner sep=2pt, draw]
  \foreach \i in {0,1,2}{
    \pgfmathsetmacro{\a}{30 + 120*\i}
    \pgfmathsetmacro{\b}{\a + 60}
    \pgfmathsetmacro{\k}{int(\i+3)}
    \node (c\i) at (\a:2) {};
    \node (s\i) at (\b:2) {};
    \node (s\k) at (\b:1) {};
    \draw[dotted] (c\i) -- (s\i);
    \draw (c\i) -- (s\k);
  }
  \foreach \i[count=\ii] in {0,1,2}{
    \pgfmathsetmacro{\j}{mod(\ii, 3)}
    \pgfmathsetmacro{\k}{\i + 3}
    \draw[dotted] (c\j) -- (s\k);
    \draw (c\j) -- (s\i);
  }
\end{tikzpicture}
\end{document}

first attempt using foreach

I expected the picture would be the same as the one below (code included):

\documentclass[tikz, border=1mm]{standalone}
\begin{document}
\begin{tikzpicture}
  \tikzstyle{every node}=[circle, inner sep=2pt, draw=black]
  \node (c0) at (30:2) {};
  \node (s0) at (90:2) {};
  \node (s3) at (90:1) {};
  \node (c1) at (150:2) {};
  \node (s1) at (210:2) {};
  \node (s4) at (210:1) {};
  \node (c2) at (270:2) {};
  \node (s2) at (330:2) {};
  \node (s5) at (330:1) {};
  \draw[dotted]
  (s0) -- (c0) -- (s5)
  (s1) -- (c1) -- (s3)
  (s2) -- (c2) -- (s4)
  ;
  \draw
  (s0) -- (c1) -- (s4)
  (s1) -- (c2) -- (s5)
  (s2) -- (c0) -- (s3)
  ;
\end{tikzpicture}
\end{document}

expected output

Question: Why is the output different in these two cases? In particular, why are the edges not anchored in the same way for these two examples?

PS. I can also automate this procedure with the expected results using three loops to (1) place coordinates, (2) draw edges, and (3) place nodes over coordinates--this question is about explaining the behaviour above.

1 Answer 1

3

The reason for the discrepancy is that you use \pgfmathsetmacro, and get numbers like 1.0, where .0 is interpreted as the east anchor of the node. A minimally invasive fix is to use \pgfmathtruncatemacro,

\pgfmathtruncatemacro{\j}{mod(\ii, 3)}
\pgfmathtruncatemacro{\k}{\i + 3}

instead.

\documentclass[tikz, border=1mm]{standalone}
\begin{document}
\begin{tikzpicture}
  \tikzstyle{every node}=[circle, inner sep=2pt, draw]
  \foreach \i in {0,1,2}{
    \pgfmathsetmacro{\a}{30 + 120*\i}
    \pgfmathsetmacro{\b}{\a + 60}
    \pgfmathsetmacro{\k}{int(\i+3)}
    \node (c\i) at (\a:2) {};
    \node (s\i) at (\b:2) {};
    \node (s\k) at (\b:1) {};
    \draw[dotted] (c\i) -- (s\i);
    \draw (c\i) -- (s\k);
  }
  \foreach \i[count=\ii] in {0,1,2}{
    \pgfmathtruncatemacro{\j}{mod(\ii, 3)}
    \pgfmathtruncatemacro{\k}{\i + 3}
    \draw[dotted] (c\j) -- (s\k);
    \draw (c\j) -- (s\i);
  }
\end{tikzpicture}
\end{document}

enter image description here

There are many ways to rewrite this, such as

\documentclass[tikz, border=1mm]{standalone}
\begin{document}
\begin{tikzpicture}
  \tikzstyle{every node}=[circle, inner sep=2pt, draw]
  \foreach \i  [evaluate=\i as \a using {30 + 120*\i}] in {0,1,2}{
    \node (c\i) at (\a:2) {};
    \node (s\i) at (\a+60:2) {};
    \node (s\the\numexpr\i+3) at (\a+60:1) {};
    \draw[dotted] (c\i) -- (s\i);
    \draw (c\i) -- (s\the\numexpr\i+3);
  }
  \foreach \i [count=\ii,
    evaluate=\ii as \j using {int(mod(\ii,3))}] in {0,1,2}{
    \draw[dotted] (c\j) -- (s\the\numexpr\i+3);
    \draw (c\j) -- (s\i);
  }
\end{tikzpicture}
\end{document}
1
  • Exactly what I was looking for; thank you!
    – User12345
    May 28, 2020 at 16:50

You must log in to answer this question.

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