Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Spirograph-like drawings are obtained when one repeatedly draws a closed curve on a continuously rotated canvas. Is there a nice way to make spirograph drawings using TikZ or PSTricks? There is a nice PSTricks example from the PracTeX journal, but it only covers the case where circles rotate about circles.

I have in mind a more general question. Is it possible to continuously rotate a parameterized, closed curve to obtain a spirographic image like the one below?

Spirographic image obtained by continuously rotating the canvas while drawing a triangle

The ideal answer to this question would be code that would allow one to specify a parameterization of a closed curve together with the number of times that the curve must repeat.

share|improve this question
1  
Could you give an example of how you'd like to specify the closed curve? –  Jake Nov 28 '11 at 2:39
    
Have you seen this? –  DJP Nov 28 '11 at 3:25
    
@DJP: That's what Serge linked to in their question. –  Jake Nov 28 '11 at 3:27
    
Sorry. How 'bout this? –  DJP Nov 28 '11 at 3:45
    
@Jake I didn't indicate how I'd like to specify the curve because I didn't want to limit the answers (and also because I was hoping for suggestions). I had in mind something like \draw plot[variable=\t,samples=100,domain=0:1] ({x(\t)},{y(\t)}); where the canvas is also rotated as a function of \t. However, I don't know how to make a piecewise function, so I didn't know where to go from here. –  Serge Nov 28 '11 at 14:23
add comment

6 Answers

up vote 7 down vote accepted

The underlying idea here is to continuously rotate the paper whilst drawing the picture with TikZ.

This is, of course, impossible.

The difficulty with this is that the resulting path from doing this wouldn't (necessarily) be composed of lines and cubic bezier curves, which is all that PGF knows how to produce.

But curves are really just lots of short straight lines, so if we replace our curve by a lot of short straight lines and rotate the endpoints of those, we might be able to achieve something. My initial idea was to use a decoration to do this, but I ran into difficulties because decorations (helpfully!) transform you into the coordinate system of the path (at the current point) whereas we want to apply a transformation that is independent of this coordinate system. Rather than pursuing that, I used some code I happened to have lying around which I developed to do more complicated stuff on paths than is currently possible. I already had code for translating a path and reversing a path, so I just needed to add incremental rotations and some window dressing.

The document code is then:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usepackage{spath}

\begin{document}
\begin{tikzpicture}
\path[decoration={curveto},decorate,save path=\tmppath] (2,0) to[bend right] (4,2) to[bend right] (5,0) to[bend right] (2,0);
\pgfoonew \opath=new spath(\tmppath)
\opath.prepare()
\opath.spirograph(,0pt,0pt,36)
\opath.use path with tikz(draw,blue)
\end{tikzpicture}
\end{document}

which looks nice and simple! Here's what it does:

  1. The \path line sets up the path which is to be repeated and twisted. It doesn't render it, but rather saves it to a macro (\tmppath). It does do one very important thing: it decorates it with the curveto decoration. This replaces the path by lots of small lines which makes the rest look much better as the rotations are applied more evenly.

  2. Next, we use this \tmppath to instantiate a "soft path object" (spath). This is using my library to allow us to manipulate the path.

  3. We prepare the path (not strictly necessary - the methods check whether or not this has been done).

  4. Now we "spirograph" the path. What happens here is that TeX walks along the path, applying a rotation to each coordinate that it reaches. Each time, it applies a rotation of a little more angle so that the path gradually bends around. Once it has done this to the original path, it then replicates this path the right number of times, copying it and welding the copies together to form a complete path around the circle.

  5. The (comma separated) arguments to the spirograph command are: 1) A macro to save the path as (empty in this case meaning that we should modify the path in place), 2) & 3) are the origin for the rotation, 4) is the number of repetitions to use going around the circle.

Result:

Spirograph image

Disadvantages:

  1. The spath library is not yet on CTAN. It is highly experimental. You can get it from the TeX-SX launchpad page (you need the latest version, I only added this today).
  2. It is extremely slow. On my system, the above took 24 seconds to compile.
  3. The path doesn't close up at the end - this is easily fixable, I just haven't done it yet.
share|improve this answer
    
aargh, there goes my many hours with literally the same idea. :) Well done! I'll have a look as soon as possible. –  percusse Mar 6 '12 at 22:12
add comment

Here is a preliminary example (depending on what you are looking for) using a for loop,

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\repeatno{40}
\node[inner sep=0.5cm,circle] (base) at (0,0) {};
\foreach \x in {1,2,...,\repeatno}{
\draw[rotate=(\x*360/\repeatno)-90] (base.\x*360/\repeatno) to [in=-70,out=70]  ++(0,2) to [in=90,out=-30] ++(1.3,-2) to [in=20,out=160] +(-1.3,0);
}
\end{tikzpicture}
\end{document}

which gives

enter image description here

Take 2 After some modification I was able to get the curve except the closing artifact. But I am really getting high with this :) Might be banned in some countries. Here is what I did (and failed slightly)

\begin{tikzpicture}
\def\repeatno{12}
\node[inner sep=0.5cm,circle] (base) at (0,0) {};
\foreach[remember=\x as \lastx (initially 1)] \x in {1,2,...,13} {
\draw[rotate=(\x*360/\repeatno)-90] (base.\x*360/\repeatno) to [in=-70,out=70]  ++(0,2)%
 to [in=90,out=-30] ++(1.3,-2) to [in=20,out=160] (base.\lastx*360/\repeatno);
}
\end{tikzpicture}

with the result (reduced the number of repetitions to make the artifact visible)

enter image description here

Seems like, I need an additional step to close the curve properly after the foreach loop. Please feel free to correct or improve

Take 3 Fixed (without the automated version, possible though)

\begin{tikzpicture}
\def\repeatno{24}
\node[inner sep=0.5cm,circle] (base) at (0,0) {};
\foreach[remember=\x as \lastx (initially 1)] \x in {2,...,23} {
\draw[rotate=(\x*360/\repeatno)-90] (base.\x*360/\repeatno) to [in=-70,out=70]  ++(0,2)%
 to [in=90,out=-30] ++(1.3,-2) to [in=20,out=160] (base.\lastx*360/\repeatno);
}
\draw[rotate=360/\repeatno-90] (base.360/\repeatno) to [in=-70,out=70]  ++(0,2)%
 to [in=90,out=-30] ++(1.3,-2) to [in=20,out=160] (base.0);
\draw[rotate=-90] (base.0*360/\repeatno) to [in=-70,out=70]  ++(0,2) to [in=90,out=-30] ++(1.3,-2) to [in=20,out=160] (base.-1*360/\repeatno);
\end{tikzpicture}

Here is the result

enter image description here

Please, let us know how exactly you want to parameterize the curve. I have used something with eye-balling but possibly you might have concrete examples in mind.

share|improve this answer
1  
I don't think this is what the OP wants: These are 40 separate triangles, but the OP is looking for for a shape drawn with a single line. –  Jake Nov 28 '11 at 3:07
1  
@Jake I also wondered about it but when I enlarged the original figure, it seems like they are individual shapes. You might be right about this, though. It is kinda hypnotizing :) –  percusse Nov 28 '11 at 3:08
    
That looks great, but I think it's not "correct" mathematically. You rotate the three corner points around the center, but I think the OP wants the rotation to be really continuous, i.e. the coordinate system has to rotate while the line is being drawn, which will turn the straight edged triangle into that trippy curvy thing. –  Jake Nov 28 '11 at 11:22
    
@Jake Ah, finally I see what you mean. Sorry for the digestion speed. :) That makes the problem more interesting but I guess one needs to have a closed form formula for that or huge number of sampling points. –  percusse Nov 28 '11 at 11:34
    
@percusse I am guilty as charged. I didn't know how to do continuous rotations, so I also just repeated a partial triangle. \begin{tikzpicture}[scale=1,line width=1pt] \begin{scope}[xshift=-7cm] \draw[color=gray] (-3,0) -- (3,0) (0,-3) -- (0,3); \draw[rotate=10,->] (1,0) -- (3,0) -- (1.5,1) --(1.1,.2); \draw[rotate=10](1.1,.2) -- (1,0); \end{scope} \foreach \theta in {0,10,20,...,360} { \begin{scope}[rotate=\theta] \draw (1,0) to[out=-5,in=200] (2.99,.1743) to[out=165,in=-40] (1.38,1.16) to[out=265,in=55] (.984,.1734); \end{scope} } \end{tikzpicture} –  Serge Nov 28 '11 at 14:34
show 1 more comment

I'm not sure to really understand the question. First I draw a closed curve and then I rotated this curve but there are no difficulty to do this, perhaps I'm on a wrong way!

First curves : the closed curve is named \myclosedcurve

\documentclass[11pt]{scrartcl}
\usepackage{tikz}

\begin{document} 

\def\spirographlike#1{%
\def\repeatno{#1}
 \foreach \i in {1,...,\repeatno}
   {%
    \begin{scope}[rotate=360/\repeatno*\i]
       \mycloedcurve
     \end{scope}}%
    } 

\def\mycloedcurve{\draw (1,0)--(-0.5,0.433)--(-0.5,-0.433)--cycle;} 
\begin{tikzpicture}
  \draw[red,->] (0,0)--(1,0) (0,0)--(0,1); \mycloedcurve 
  \end{tikzpicture} 
\begin{tikzpicture}[scale=4]
\spirographlike{24}
\end{tikzpicture}    

\def\mycloedcurve{ \draw (1,0)--(2,0.433)--(0.5,0.866)--cycle;} 
\begin{tikzpicture}
  \draw[red,->] (0,0)--(1,0) (0,0)--(0,1); \mycloedcurve 
  \end{tikzpicture}
\begin{tikzpicture}[scale=2]
\spirographlike{36}
\end{tikzpicture}  

\end{document} 

enter image description here

2) a more complicated curve, I used my package tkz-fctto draw this one

\documentclass[11pt]{scrartcl}
\usepackage{tkz-fct}

\begin{document} 

\def\spirographlike#1{%
\def\repeatno{#1}
 \foreach \i in {1,...,\repeatno}
   {%
    \begin{scope}[rotate=360/\repeatno*\i]
      \mycloedcurve
    \end{scope}}%
    } 
\def\mycloedcurve{\tkzFctPolar[domain=0:2*pi,samples=400]{ 1-sin(t)}}  

\begin{tikzpicture}
  \draw[red,->] (0,0)--(1,0) (0,0)--(0,1); \mycloedcurve 
\end{tikzpicture}    
\begin{tikzpicture}[scale=2]
 \tkzInit [xmin=-5,xmax=5,ymin=-5,ymax=5] 
  \spirographlike{40}    
\end{tikzpicture} 

\end{document} 

enter image description here

share|improve this answer
    
I think the OP wants to draw the whole graph with a single line, without "lifting the pen off the paper", so to speak. Basically, it would be like drawing the same shape n times, and continuously rotating the paper underneath, not rotating it by 360/*n* degrees after each repetition. –  Jake Nov 28 '11 at 10:41
    
@Jake ok I don't understand the example given by the OP with the triangle and the graph. The problem needs to be solved with mathematics before to draw something with TeX! No? –  Alain Matthes Nov 28 '11 at 11:12
    
@Jake The main question and problem is : ` Is it possible to continuously rotate with Pstricks or Tikz`? –  Alain Matthes Nov 28 '11 at 11:14
1  
Yeah, I think the first bit is to parametrise the triangle. It would be some ugly discontinuous periodic function x(t) = g(t) and y(t) = j(t), and to get the rotation it would become x*(t) = g(t) + sin(t), y(t) = j(t) + cos(t). –  Jake Nov 28 '11 at 11:19
add comment

I have a solution, though it's not quite what I had envisioned. From the answers (and lack of answers) I have come to believe that continuous rotations are not a built-in feature of tikz, so I took the suggestions of Jake and Altermundus to just program in all the math calculations myself using polar coordinates. Below is my solution and its output.

% Parameterize piecewise function via functions x(t) and y(t).
\newcommand{\xPieceA}[1]{(-1+4*#1)}
\newcommand{\xPieceB}[1]{(5-2*#1)}
\newcommand{\xPieceC}[1]{(4-2*#1)}

\newcommand{\yPieceA}[1]{-.5*sin(360*#1)}  
\newcommand{\yPieceB}[1]{(2-2*#1)}
\newcommand{\yPieceC}[1]{(-6+2*#1)}

\pgfmathdeclarefunction{x}{1}{%
  \pgfmathparse{((and(Mod(#1,3)>=0, Mod(#1,3)<1)*\xPieceA{Mod(#1,3)})
+(and(Mod(#1,3)>=1, Mod(#1,3)<2)*\xPieceB{Mod(#1,3)})
+(and(Mod(#1,3)>=2,Mod(#1,3)<3)*\xPieceC{Mod(#1,3)}))}%
}

\pgfmathdeclarefunction{y}{1}{%
  \pgfmathparse{((and(Mod(#1,3)>=0, Mod(#1,3)<1)*\yPieceA{Mod(#1,3)})
+(and(Mod(#1,3)>=1, Mod(#1,3)<2)*\yPieceB{Mod(#1,3)})
+(and(Mod(#1,3)>=2,Mod(#1,3)<3)*\yPieceC{Mod(#1,3)}))}%
}

% Plot the original shape and its spirograph image
\begin{tikzpicture}[line width=1pt]
\draw[xshift=-8cm,->] plot[variable=\t,samples=200,domain=3:6] ({x(\t)},{y(\t)});
\draw[xshift=-8cm,<->,red] (0,1) -- (0,0) -- (1,0);
\draw plot[variable=\t,samples=1600,domain=0:60] ({6*\t+atan(y(\t)/x(\t))}: {(sqrt(abs(x(\t)))^2+(abs(y(\t)))^2)});
\end{tikzpicture}

Cool spirograph curve

I am sure that this is not optimal, but it does work and it has the feature that percusse suggested that the original curve does not need to be closed. Perhaps it would compile faster if it called on gnuplot to do the calculations.

Please continue to make suggestions and improvements.

share|improve this answer
add comment

At TeXample.net there is an example of a "Rose rhodonea curve" here:

http://www.texample.net/tikz/examples/rose-rhodonea-curve/

share|improve this answer
    
The Rose rhodonea curve is indeed a beautiful example of tikz code. Thanks for pointing it out. Of course my hope on this question is an answer that allows me to easily specify a closed curve (ideally without having to manually convert it to polar coordinates). –  Serge Nov 28 '11 at 2:23
add comment

With PSTricks.

Heart

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-plot}
\psset{linejoin=1,algebraic,dimen=monkey,linecolor=red,plotpoints=100}

\def\N{6}
\def\R{2}
\def\heart{\psparametricplot{0}{2 Pi mul}{sin(t)^3 | (13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t))/16}}
\degrees[\N]

\begin{document}
\begin{pspicture}(-3,-3)(3,3)
    \pscircle[linecolor=blue,linestyle=dashed]{\R}
    \multido{\i=0+1}{\N}{\uput{\R}[\i]{\i}{\heart}}
\end{pspicture}
\end{document}

enter image description here

For N=50.

enter image description here

share|improve this answer
    
That doesn’t look right … –  Qrrbrbirlbel Nov 6 '13 at 6:06
    
@Qrrbrbirlbel: What? I don't understand. :-) –  I am who I say I am Nov 6 '13 at 6:21
    
“… a continuously rotated canvas”. The heart is drawn at once at one angle. Text and image of the accepted answer and percusse’s show very good. –  Qrrbrbirlbel Nov 6 '13 at 6:25
    
@Qrrbrbirlbel: OK. I understood now. But I will edit it later as there is another thing to do right now. –  I am who I say I am Nov 6 '13 at 6:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.