29

I want to use tikz to draw a golden spiral, growing clockwise, ideally (but not necessarily) superimposed over a set of golden rectangles (you all know the image I'm talking about). A little bit of searching led me to this code, which yields a counterclockwise spiral:

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings,calc}
\tikzset{nctopath/.style={
     to path=(\tikztostart) ..controls ($(\tikztostart)!1cm*#1!-90:(\tikztotarget)$) and 
        ($(\tikztotarget)!($(\tikztostart)!1cm*#1!-50:(\tikztotarget)$)!70:    (\tikztostart)$).. 
    (\tikztotarget)
    },
}
\begin{document}    
\begin{tikzpicture}
\def\totx{1}
\coordinate (n-1-1) at (0,0) {};
\foreach \x[count=\xi from 2, evaluate=\x as \temptotx using int(\x+\totx)] in {1,...,9}{
\draw[decoration={
    markings,mark=between positions 0 and 1 step 0.249 with {
            \coordinate (n-\x-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number})     ;
        }
   },postaction=decorate
] 
(n-\x-1) arc (\x*90+180:(\x+1)*90+180:{(\temptotx)*3mm}) 
coordinate (n-\xi-1) 
\pgfextra{\xdef\totx{\temptotx}};
}

\end{tikzpicture}
\end{document}

The thing is that I'm still new to tikz and thus not sure what code here does what. My questions are:

  1. How do I reverse the growth direction?

  2. How do I set phi as the growth factor (which I don't think it is currently, just from looking at the resulting spiral)?

  3. How cumbersome would it be to add in the golden rectangles (i.e., would I have to draw each one individually, or is there some way to define a pattern)?

crmdgn
  • 2,628

3 Answers3

61

Basically, the same approach as JLDiaz but using a recursive macro and letting tikz scopes and transformations do all the work.

\documentclass[tikz, border=0.125cm]{standalone}
\begin{document}

\def\spiral#1{%
  \pgfmathparse{int(#1)}%
  \ifnum\pgfmathresult>0
    \draw [help lines] (0,0) rectangle ++(1,1);
    \begin{scope}[shift={(1,1)}, rotate=90, scale=1/1.6180339887]
      \spiral{#1-1}
    \end{scope}
    \draw [red] (0,0) arc (270:360:1);
  \fi
}

\tikz[scale=2]{\spiral{12}}

\end{document}

enter image description here

And perhaps...

\documentclass[border=0.125cm, tikz]{standalone}

\begin{document}

\def\spiral#1#2#3{%
  \pgfmathparse{int(#1)}%
  \ifnum\pgfmathresult>0
    \draw [help lines] (0,0) rectangle ++(1,1);
    \begin{scope}[shift={(1,1)}, rotate=#2, scale=1/#3]
      \spiral{#1-1}{#2}{#3}%
    \end{scope}
    \pgfmathparse{int(\a)}%
    \ifnum\pgfmathresult=0
      \draw [red] (0,0) -- (1,1);
    \else%
      \draw [red] (0,0) arc (270+45-#2/2:360-45+#2/2:{1/sqrt(2) / sin(#2/2)});
    \fi
  \fi
}

\foreach \a in {90,85,...,-90,-85,-80,...,85}{
 \tikz[scale=2]{\spiral{12}{\a}{1.6180339887}\useasboundingbox (-0.5,-0.5) rectangle (3.5,3.5);}
}

\end{document}

enter image description here

Mark Wibrow
  • 70,437
  • 2
    +1 the spiral gets drawn on top of the squares, without need of layers. Smart! – JLDiaz Nov 23 '13 at 19:06
  • 11
    What a nice animation! – juliohm Nov 23 '13 at 23:32
  • Whoa! How did you do the animation? – crmdgn Nov 24 '13 at 16:03
  • @crmdgn gimp is ideal for this kind of thing. – Mark Wibrow Nov 24 '13 at 18:57
  • As in gimp the photo editor? or is there a gimp TeX package? – crmdgn Nov 24 '13 at 20:35
  • @crmdgn: There are many answers about creating GIF animations for you: http://tex.stackexchange.com/a/74076/19356 – kiss my armpit Nov 24 '13 at 20:53
  • OK, new development: when I use this code in a document, the spiral appears on top of the document text, several lines below where the figure is supposed to be. Anyone know how to address that issue? – crmdgn Nov 25 '13 at 00:48
  • @crmdgn You simply import the resulting pdf into gimp. You can then preview/optimize the animation and export to gif. – Mark Wibrow Nov 25 '13 at 07:10
  • @crmdgn it depends on how you are putting the image into the document, but if you are using the second code example a gap will be caused by the \useasboundingbox which was used to ensure that the picture was the same size and the spiral positioned identically on each page/frame. The first example should have no gap. – Mark Wibrow Nov 25 '13 at 07:12
27

Code

Improved a little the code to make easier the explanations, and to put the "golden ratio rectangles" in a background layer. Explanations below the picture.

Updated after egreg's comments.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\thispagestyle{empty}
\usetikzlibrary{calc}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\newcommand\GoldenRatio{1.6180339887}
\newcommand\Side{10}
\newcommand\Sqrtwo{1.4142135624}

\begin{tikzpicture}[line cap=round]
\coordinate (origin) at (0,0);
\foreach \angle in {0,90,...,1000} {
  \coordinate (corner) at ($(origin)+(45+\angle:\Side*\Sqrtwo)$);
  \begin{pgfonlayer}{background}
      \draw[help lines] (origin) rectangle (corner);
  \end{pgfonlayer}
  \draw[very thick,red] (origin) arc(\angle-90:\angle:\Side);
  \coordinate (origin) at (corner);
  \pgfmathsetmacro{\Side}{\Side/\GoldenRatio}
  \xdef\Side{\Side}
}
\end{tikzpicture}
\end{document}

Result

Result

Explanations

The picture is built recursively, from a fundamental building block, which is a square containing a red arc.

The square is defined from two points. The first one is called origin, and initially is located at (0,0), but it will move in successive iterations of the loop. The second one is called corner, and its coordinates are dependent of those of origin in the following way:

  \coordinate (corner) at ($(origin)+(45+\angle:\Side*\Sqrtwo)$);

The expression +(45+\angle:\Side*\Sqrtwo) uses polar coordinates, relative to origin. The angle is 45 plus the "current angle" (initially zero), and the distance is the diagonal of the square whose side has \Side units of length.

Once origin and corner are known, the building block is drawn as (omitted in this case the background layer for clarity):

  \draw[help lines] (origin) rectangle (corner);
  \draw[very thick,red] (origin) arc(\angle-90:\angle:\Side);

In the first iteration, since \angle=0, \Side=10, this produces the following building block, whose side has 10 units of length:

Building block

Now, the neat trick is to update all the variables which define the building block, so that the next building block has:

  • Its origin at the previous block corner
  • Its \angle increased in 90 degrees
  • Its \Side reduced in the golden ratio.

This is the role of the next lines:

  \coordinate (origin) at (corner);
  \pgfmathsetmacro{\Side}{\Side/\GoldenRatio}
  \xdef\Side{\Side}

The following figure shows the two first iterations, and thus the two first building blocks. I decided to draw also in blue the vector which places the "corner" relative to the origin, to better understand the procedure:

Two steps

And so on, at each step the building block is reduced by the golden ratio, rotated 90 degrees, and shifted to the latest "corner".

JLDiaz
  • 55,732
  • I'll be damned. That's exactly what I need. Super curious to see the explanation, whenever you have time. – crmdgn Nov 23 '13 at 15:44
  • @crmdgn Also note that what I have drawn is an approximation of a "true" golden spiral, as noted here – JLDiaz Nov 23 '13 at 16:18
  • Very good answer; I have two remarks, though. Don't use \def, first of all, much less redefine \Phi in the open. Then, what's the sense of giving the golden ratio with three decimal digits and the square root of 2 with nineteen? – egreg Nov 23 '13 at 16:19
  • @egreg What's the issue with \def and with defining \Phi? – crmdgn Nov 23 '13 at 16:27
  • @JLDiaz what defines the number of iterations in the drawing? – crmdgn Nov 23 '13 at 16:28
  • @egreg You are right about \Phi, I'll update the answer. However, why not using \def? What instead, \newcommand? – JLDiaz Nov 23 '13 at 16:34
  • 1
    @JLDiaz With \newcommand{\Phi}{1.618} you'd have been warned that \Phi is already defined. – egreg Nov 23 '13 at 16:36
  • @crmdgn \Phi is already defined. What if you use \Phi in a subsequent math formula? With that code it would print 1.618, which of course is not what you want. – egreg Nov 23 '13 at 16:37
  • @crmdgn There is a \foreach \angle in {...} loop, which gives succesive values to the variable \angle at increments of 90 degrees. It stops when \angle>1000, so there are 12 iterations in my drawing (12*90=1080). – JLDiaz Nov 23 '13 at 16:46
  • Hm. New question: when I try to run this code I get a lot of error messages about ''illegal unit of measure'' and ''dimension too large'' and other stuff. The drawing comes out odd, too; I'd post it to show you but I don't think I can. Any idea what might be causing that? – crmdgn Nov 23 '13 at 17:16
  • @crmdgn No idea... The code had a bug (it still used \Phi instead of \GoldenRatio at a point), but this wouldn't cause the problem you describe. I fixed it anyway. Did you directly tried my example or you inserted it into another document? If the second, the problem it should be somewhere in your document. – JLDiaz Nov 23 '13 at 18:24
17

Just for fun with PSTricks. No recursively-invoked macro is used here. Instead, the next node is determined by the previous one in a loop.

Linear complexity

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node,multido}
\psset{dimen=monkey}

\pstVerb
{
    /R   5 def
    /P   {2 5 sqrt 1 add div} def
    /p   {1 P div} def
    /OmP {1 P sub} def
    /C   {2 sqrt mul 45 PtoC} def
}

\def\Atom#1{%
\begin{pspicture}(-4,-1)(6,6)
    \pnode(!p 1 sub R mul neg 0 ){A-1}
    \multido{\ic=0+1,\ip=-1+1}{#1}
    {%
        \nodexn{(A\ip)+(!\ic\space dup 1 sub P exch exp R mul OmP mul exch 90 mul PtoC)}{A\ic}
        \rput(A\ic){\rput{!90 \ic\space mul}(0,0){\psframe(!R P \ic\space exp mul C)}}
    }
    \pscustom[linecolor=red]{\multido{\ic=0+1}{#1}{\psarc(A\ic){!R P \ic\space exp mul}{!\ic\space 90 mul}{!\ic\space 90 mul 90 add}}}
\end{pspicture}}

\begin{document}
\multido{\i=0+1}{12}{\Atom{\i}}
\end{document}

enter image description here

Quadratic complexity

It is not recommended as creating the i-th node needs i iterations.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node,pst-plot}
\psset{dimen=monkey}

\pstVerb
{
    /R   5 def
    /P   {2 5 sqrt 1 add div} def
    /p   {1 P div} def
    /OmP {1 P sub} def
    /C   {2 sqrt mul 45 PtoC} def
}

\def\Atom#1{%
\begin{pspicture}(-4,-1)(6,6)
    \curvepnodes[plotpoints=#1]{0}{\the\numexpr#1-1\relax}
    {
        p 1 sub R mul neg 0 
        0 1 t
        {
          dup 1 sub P exch exp R mul OmP mul exch 90 mul PtoC
            3 -1 roll add 3 1 roll add exch 
        } for 
    }{A}
    \multido{\ic=0+1}{#1}{\rput(A\ic){\rput{!90 \ic\space mul}(0,0){\psframe(!R P \ic\space exp mul C)}}}
    \pscustom[linecolor=red]{\multido{\ic=0+1}{#1}{\psarc(A\ic){!R P \ic\space exp mul}{!\ic\space 90 mul}{!\ic\space 90 mul 90 add}}}
\end{pspicture}}

\begin{document}
\multido{\i=2+1}{12}{\Atom{\i}}
\end{document}

Closed form

In progress...

  • I will edit this answer later as I have many things to do right now. The quadratic complexity can be converted to be linear with temporary variables as explained by Christoph in another topic on this site. – kiss my armpit Nov 26 '13 at 22:14