6

I am trying to recreate a triangle spiral(red) with a foreach -but the turn option does not behave nicely - it seems to turn less and less each time. Is there an explanation? What am I doing wrong?

Here I use 90 degree angle and length 1, just to illustrate:

\documentclass[tikz, border=1 cm]{standalone}
\begin{document}
\begin{tikzpicture}
\newcommand{\x}{0.872}
\draw[red] (0,0) -- (1,0)
  -- ([turn]125:\x^1)
  -- ([turn]125:\x^2) 
  -- ([turn]125:\x^3) 
  -- ([turn]125:\x^4) 
  -- ([turn]125:\x^5) 
  -- ([turn]125:\x^6) 
  -- ([turn]125:\x^7) 
  -- ([turn]125:\x^8) 
  -- ([turn]125:\x^9) 
  -- ([turn]125:\x^10);
\draw (0,0) -- (1,0) foreach \i in {1,...,50} {-- ([turn]90:1)};
\end{tikzpicture}
\end{document}

Red triangle spiral and large black spiral

Edit:

With \draw (0,0) -- (1,0) foreach \i in {1,...,10} { -- ([turn]125:\x^\i)}; I get:

Different red and black spirals

3
  • Just to clarify, you expect the code in the second statement to produce a black square (with each side being drawn ~12 times)?
    – Marijn
    Sep 16, 2021 at 12:04
  • Yes. And I would expect this to recreate red spiral \draw (0,0) -- (1,0) foreach \i in {1,...,10} { -- ([turn]125:\x^\i)}; (but it does not) Sep 16, 2021 at 12:07
  • It seems that is a bug!
    – Black Mild
    Sep 16, 2021 at 12:18

2 Answers 2

6

I agree with Black Mild in comment that this seems a tikz bug, and has reported it here: https://github.com/pgf-tikz/pgf/issues/1047.

A possible fix:

\documentclass{article}
\usepackage{tikz}

\makeatletter
% see https://github.com/pgf-tikz/pgf/blob/85d2c38b78407e5b1ba42140dfd11fcdf8df1edf/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex#L2582-L2616
\def\tikz@foreach{%
  \def\pgffor@beginhook{%
    \tikz@lastx=\tikz@foreach@save@lastx%
    \tikz@lasty=\tikz@foreach@save@lasty%
    \tikz@lastxsaved=\tikz@foreach@save@lastxsaved%
    \tikz@lastysaved=\tikz@foreach@save@lastysaved%
    \let\tikz@tangent=\tikz@foreach@save@tangent % added
    \setbox\tikz@figbox=\box\tikz@tempbox%
    \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg%
    \expandafter\tikz@scan@next@command\pgfutil@firstofone}%
  \def\pgffor@endhook{\pgfextra{%
      \xdef\tikz@foreach@save@lastx{\the\tikz@lastx}%
      \xdef\tikz@foreach@save@lasty{\the\tikz@lasty}%
      \xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}%
      \xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
      \global\let\tikz@foreach@save@tangent=\tikz@tangent % added
      \global\setbox\tikz@tempbox=\box\tikz@figbox%
      \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg%
      \pgfutil@gobble}}%
  \def\pgffor@afterhook{%
    \tikz@lastx=\tikz@foreach@save@lastx%
    \tikz@lasty=\tikz@foreach@save@lasty%
    \tikz@lastxsaved=\tikz@foreach@save@lastxsaved%
    \tikz@lastysaved=\tikz@foreach@save@lastysaved%
    \let\tikz@tangent=\tikz@foreach@save@tangent % added
    \let\pgffor@beginhook\relax%
    \let\pgffor@endhook\relax%
    \let\pgffor@afterhook\relax%
    \setbox\tikz@figbox=\box\tikz@tempbox%
    \setbox\tikz@figbox@bg=\box\tikz@tempbox@bg%
    \tikz@scan@next@command}%
  \global\setbox\tikz@tempbox=\box\tikz@figbox%
  \global\setbox\tikz@tempbox@bg=\box\tikz@figbox@bg%
  \global\let\tikz@foreach@save@tangent=\tikz@tangent % added
  \xdef\tikz@foreach@save@lastx{\the\tikz@lastx}%
  \xdef\tikz@foreach@save@lasty{\the\tikz@lasty}%
  \xdef\tikz@foreach@save@lastxsaved{\the\tikz@lastxsaved}%
  \xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
  \foreach}%
\makeatother

\begin{document}
\newcommand{\x}{0.872}

\begin{tikzpicture}
  \draw (0,0) -- (1,0) foreach \i in {1,...,50} {-- ([turn]90:1)};
  
  \draw[xshift=2cm] (0,0) -- (1,0) foreach \i in {1,...,10} { -- ([turn]125:\x^\i)};
\end{tikzpicture}
\end{document}

output: enter image description here


To save some lines,

\usepackage{regexpatch}

\makeatletter
\xpatchcmd*\tikz@foreach
  {\tikz@lastysaved=\tikz@foreach@save@lastysaved}
  {\tikz@lastysaved=\tikz@foreach@save@lastysaved
   \let\tikz@tangent=\tikz@foreach@save@tangent}
  {}{\PatchFailed}

\xpatchcmd*\tikz@foreach
  {\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}}
  {\xdef\tikz@foreach@save@lastysaved{\the\tikz@lastysaved}%
   \global\let\tikz@foreach@save@tangent=\tikz@tangent}
  {}{\PatchFailed}
\makeatother
2
  • Thanks. I was hoping that I could just use an extra pair of parentheses or something stupid like that. Is your fix just for this specific case, or is it more like an actual repair of TikZ? Sep 16, 2021 at 22:41
  • 1
    It tries to fix turn used in foreach loop body. Sep 17, 2021 at 0:11
7

It seems like foreach doesn't work well with [turn]. I couldn't find a way to fix your issue. Anyway, I suggest that you use only the robust commands to do that. Maybe like this:

foreach lines

\documentclass[tikz, border=3.14mm]{standalone}
\begin{document}
    \begin{tikzpicture}
        \def\x{0.87}
        \draw (0,0) foreach \i in {1,...,50} {--++(125*\i:3*\x^\i)};
    \end{tikzpicture}
\end{document}
3
  • 1
    I can not remember, but are there not a relative low limit on what angle is allowed in polar coordinates? -I am surprised that 125*50 is accepted. Sep 16, 2021 at 16:10
  • Actually, I suspected a dimension too large error to happen, but it didn't. Don't really know if there's a substatntial limit. We could try.
    – SebGlav
    Sep 16, 2021 at 17:30
  • 1
    By test the angle accepts: -16383.99999 to 16383.99999. -but the manual page 138 says: "The angle must always be given in degrees and should be between −360 and 720." Sep 16, 2021 at 20:21

You must log in to answer this question.

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