%% $Id: pst-spirograph-doc.tex 1233 2026-04-12 08:12:46Z herbert $
\documentclass[11pt,english,BCOR10mm,DIV12,bibliography=totoc,parskip=false,smallheadings,
    headexclude,footexclude,oneside]{pst-doc}
\errorcontextlines=150
\usepackage{pst-spirograph}
\let\pstFV\fileversion
\usepackage{minted-code}
\usepackage{pst-node,pst-plot}
\usepackage{animate}

\def\UrlFont{\small\ttfamily}
\makeatletter
\def\verbatim@font{\small\normalfont\ttfamily}
\makeatother

\hypersetup{pdfauthor={Manuel Luque, Herbert Voss},pdftitle={Spirograoh}}
%

\lstset{basicstyle=\ttfamily\footnotesize}

\addbibresource{\jobname.bib}


\begin{document}
\author{Manuel Luque\\Herbert Vo\ss}
\docauthor{}
\date{\today}
\title{pst-spirograph \\\small v.\pstFV}
\subtitle{A PSTricks package for drawing spirograph curves}
\maketitle%

\tableofcontents

\begin{abstract}
\vfill\noindent
Thanks for feedback and contributions to:\\
Uwe Ziegenhagen;
\end{abstract}

\clearpage

\section{Introduction}


\LPack{pst-spirograph} is a package to simulate the operation of a spirograph. A spirograph
is a geometric drawing toy that produces mathematical roulette curves that are technically
known as hypotrochoids and epitrochoids.
The mathematician Bruno Abakanowicz invented the spirograph between 1881 and 1900.%
\footnote{\url{http://en.wikipedia.org/wiki/Spirograph}}
It was used to calculate an area delimited by curves.
A hypotrochoid is generated by a fixed point on a circle rolling inside a fixed circle.%
\footnote{\url{http://mathworld.wolfram.com/Spirograph.html}}
It consists of a small toothed wheel rotating inside or outside a ring gear.
The weighing tile wheel has nine drilled holes numbered from 0--8, through these small holes the tip of a 
pen or pencil can be put.
This causes the small wheel to rotate one or more laps around the crown and draws a hypocycloid.

The wheel can also turn off a first fixed gear, it is thus possible to draw epicycloids . The command is written as 


\begin{BDef}
\Lcs{psSpirograph}\OptArgs\Largr{\CAny}\\
\Lcs{psSpirographB}\OptArgs\Largr{\CAny}
\end{BDef}


and can optionally be followed by the coordinates of the point where you wish to place the
Spirograph: \Lcs{psSpirograph}\OptArgs\Largr{x,y} which by default is centered at the origin.
The optional parameters, including default values are indicated as following:

\begin{compactenum}
\item \LKeyset{Z1=20}: number of teeth of the wheel 1, the crown;
\item \LKeyset{Z2=10}: number of teeth of the wheel 2;
\item \LKeyset{m=0.5}: relative size of the gear;
\item \LKeyset{ap=20}: pressure angle in degrees, it must be reduced if the number of teeth
    crown is large (if the path of the teeth will be incorrect), e.g. take \verb|Z1=120|;
\item \LKeyset{holenumber=0}: active hole number;
\item \LKeyset{polarangle=0}: polar angle in degrees to position the center of the inner/outer gear;
of the small wheel. It is a useful parameter for an animation, then it is the starting angle..
\item \LKeyset{thetamax=360}: the end value for the rotation of the second  inside/outside gear;
\end{compactenum}

There are two Boolean values for the organisation of the two circles:

\begin{compactitem}
\item \Lkeyword{circles}: to draw circles of contact (default is \texttt{false}.
\item \Lkeyword{inner}: the gear rotates inside of the crown (\texttt{true} --- default) or outside (\texttt{false}).
\end{compactitem}


In the drawing, the color selection wheel and the line of the curve is made with
the following setting:


\begin{compactenum}
\item \LKeyset{color1=\{[rgb]\{0.625 0.75 1\}\}};
\item \LKeyset{color2=\{[rgb]\{0.75 1 0.75\}\}};
\item \Lkeyset{curvecolor=red};
\item \LKeyset{curvewidth=1pt}: linewidth of the hypocycloid;
\item \Lkeyset{circlescolor=red}.
\end{compactenum}

The origin of the spirograph can be set by the coordinates $(x,y)$. If the they are missing, $(0,0)$ is assumed.
By default, the wheels are not filled with color. The color inside the wheels must be
set by the option \Lkeyset{fillStyle=solid}.

The choice of color and line thickness contour of the wheels is made with
usual PSTricks options: \Lkeyword{linecolor} and \Lkeyword{linewidth}.
The transparency of the small wheel is adjusted with the \Lkeyword{opacity} option of PSTricks.

The last parameter is the angle \LKeyset{thetamax=360}, which represents the rotation in degrees
the center of the small wheel around the ring, so it is a parameter to adjust,
depending on the planned route of the hypocycloid.


\section{Parameter}

\subsection{Relative size}
The relative size of the two gears can be set by the optional argument \Lkeyword{m},
which can take every possible value.


%\begin{LTXexample}[pos=t]
\begin{exampleM}{{inner=false,m=0.1,polarangle=200,holenumber=0}}
\psset{unit=0.5}
\begin{pspicture}[showgrid=top,opacity=0.5](-11,-11)(11,11)
\psframe*[linecolor=yellow!30](-11,-11)(11,11)
\psset{thetamax=720,Z1=120,Z2=48,ap=10,linewidth=0.025,fillstyle=solid}
\psSpirograph[inner=false,m=0.1,polarangle=200,holenumber=0,linecolor=blue,curvecolor=blue]
\psSpirograph[m=0.1,polarangle=200,holenumber=0,linecolor=red]
\end{pspicture}
\end{exampleM}
%\end{LTXexample}





\subsection{Pencil position}

\noindent\begin{tabularx}{\linewidth}{@{} XX @{}}
The holes (\Lkeyword{holenumber}) for the pencil are ordered from outside into the center of the gear with different
polar coordinates (radius and angle) . They are numbered from 0 to 8 and the position cannot be changed. Every given number greater
than 8 will be reset internally to 8.
&
\begin{pspicture}[shift=-5cm](-3.5,-3.5)(3.5,3.5)
  \pscircle*[linecolor=red!30](0,0){3}
    \psaxes[axesstyle=polar,labels=none](3,360)
    \multido{\iA=0+60,\iB=8+-1}{9}{%
    \pnode(!0.35 \iA\space DegtoRad mul \iA\space cos mul neg
            0.35 \iA\space DegtoRad mul \iA\space sin mul){N\iB}%
    \psdot(N\iB)\uput[0](N\iB){\iB}}
  \pscurve{->}(N0)(N1)(N2)(N3)(N4)(N5)(N6)(N7)(N8)
\end{pspicture}
\end{tabularx}


\begingroup
\begin{exampleM}{holenumber}
\psset{unit=0.8cm}
\begin{pspicture}[showgrid=top,opacity=0.5](-7,-7)(7,7)
\psframe*[linecolor=yellow!30](-7,-7)(7,7)
\psset{thetamax=720,Z1=120,Z2=48,m=0.1,ap=10,linewidth=0.025,curvewidth=1.1pt}
\psSpirograph[holenumber=0]
\psSpirograph[holenumber=1,curvecolor=blue]   \psSpirograph[holenumber=2,curvecolor=green]
\psSpirograph[holenumber=3,curvecolor=cyan]   \psSpirograph[holenumber=4,curvecolor=magenta]
\psSpirograph[holenumber=6,curvecolor=black]  \psSpirograph[holenumber=5,curvecolor=black!50]
\psSpirograph[holenumber=7,curvecolor=blue!50]\psSpirograph[holenumber=8,curvecolor=red!50]
\end{pspicture}
\end{exampleM}
\endgroup


\clearpage
\subsection{Pressure Angle}

This value defines the look of a ``teeth''. Values greater than 30 make no real sense.

\begingroup
\begin{exampleM}{{ap, holenumber}}
\psset{unit=1cm}
\begin{pspicture}[showgrid=top,opacity=0.5](-7,-3)(7,3)
\psset{unit=0.4,linewidth=0.025,fillstyle=solid,polarangle=90}
\psSpirograph[ap=0](-12,0) 
\psSpirograph[ap=20, holenumber=4](0,0) 
\psSpirograph[ap=30, holenumber=8](12,0)
\end{pspicture}
\end{exampleM}
\endgroup

\clearpage


\section{Examples}

%\psset{unit=1cm}
\begingroup
\begin{exampleM}{{thetamax=720,Z1=120,Z2=48,m=0.1,ap=10}}
\psset{unit=1cm}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=yellow!30](-7,-7)(7,7)
\psSpirograph[thetamax=720,Z1=120,Z2=48,m=0.1,ap=10,linewidth=0.025,
    fillstyle=solid,polarangle=200,holenumber=0,opacity=0.3]
\psSpirograph[thetamax=720,Z1=120,Z2=48,m=0.1,ap=10,linewidth=0.025,
    fillstyle=solid,polarangle=340,holenumber=3,opacity=0.3,curvecolor=blue]
\psSpirograph[thetamax=720,Z1=120,Z2=48,m=0.1,ap=10,linewidth=0.025,
    fillstyle=solid,polarangle=90,holenumber=6,opacity=0.3,curvecolor=green]
\end{pspicture}
\end{exampleM}
\endgroup

\begingroup
\begin{exampleM}{{thetamax=720,Z1=120,Z2=48,m=0.1,ap=10}}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=yellow!30](-7,-7)(7,7)
\psSpirograph[thetamax=720,Z1=120,Z2=48,m=0.1,ap=10,linewidth=0.025,
              fillstyle=solid,polarangle=200,holenumber=3,opacity=0.75]
\end{pspicture}
\end{exampleM}
\endgroup



\begingroup
\begin{exampleM}{{thetamax=720,Z1=36,Z2=24,m=0.15}}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=gray!20](-7,-7)(7,7)
\psSpirograph[thetamax=720,Z1=36,Z2=24,m=0.15,linewidth=0.025,ap=20,inner=false,
  fillstyle=solid,polarangle=150,linecolor=blue,holenumber=0,opacity=0.8]
\end{pspicture}
\end{exampleM}
\endgroup

\begingroup
\begin{exampleM}{{thetamax=1440,Z1=27,Z2=12,m=0.4}}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=yellow!30](-7,-7)(7,7)
\psSpirograph[thetamax=1440,Z1=27,Z2=12,m=0.4,linewidth=0.025,
  curvecolor={[rgb]{0 0.25 0.5}},circles,fillstyle=solid,polarangle=30,
  linecolor=blue,holenumber=0,opacity=0.75]
\end{pspicture}
\end{exampleM}
\endgroup

\begingroup
\begin{exampleM}{{thetamax=-1800,Z1=108,Z2=15,m=0.2,ap=10,polarangle=54}}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=yellow!30](-7,-7)(7,7)
\psset{unit=0.5}
\psSpirograph[thetamax=-1800,Z1=108,Z2=15,m=0.2,linewidth=0.025,ap=10,
  fillstyle=solid,polarangle=54,linecolor=blue,holenumber=0,opacity=0.75]
\end{pspicture}
\end{exampleM}
\endgroup


\begingroup
\begin{exampleM}{{thetamax=1800,Z1=36,Z2=30,m=0.15,ap=20,inner=false,polarangle=150,holenumber=4}}
\begin{pspicture}[showgrid=top](-7,-7)(7,7)
\psframe*[linecolor=gray!20](-7,-7)(7,7)
\psSpirograph[thetamax=1800,Z1=36,Z2=30,m=0.15,linewidth=0.025,ap=20,inner=false,
  fillstyle=solid,polarangle=150,linecolor=blue,holenumber=4,opacity=0.8]
\end{pspicture}
\end{exampleM}
\endgroup

\clearpage
\section{Animations}

\begin{sloppypar}
With package \LPack{animate} one can easily create animations. You get a better result with
\verb:\multiframe{360}{iA=0+4}{...}: but that increases the file size of the PDF. To save diskspace the following
examples use a bigger angle step than useful for a single animation.
\end{sloppypar}



\begingroup
%\psset{unit=0.75cm}
%\begin{LTXexample}[pos=t]
\begin{animateinline}[
  width=0.9\linewidth,
  begin={\begin{pspicture}(-4,-4)(4,4)},
  end={\end{pspicture}},
  palindrome,controls,
%  autoplay
]{5}
\multiframe{80}{iA=0+10}{%
  \psSpirograph[thetamax=\iA,Z1=59,Z2=24,m=0.1,ap=10,curvewidth=1.1pt,
    linewidth=0.025,fillstyle=solid,polarangle=\iA,holenumber=5,opacity=0.5](0,0)}
\end{animateinline}
%\end{LTXexample}
\endgroup

\begin{codeblockA}[title=First animation]
%\psset{unit=0.75cm}
\begin{animateinline}[
  width=0.9\linewidth,
  begin={\begin{pspicture}(-4,-4)(4,4)},
  end={\end{pspicture}},
  palindrome,controls,
%  autoplay
]{5}
\multiframe{80}{iA=0+10}{%
  \psSpirograph[thetamax=\iA,Z1=59,Z2=24,m=0.1,ap=10,curvewidth=1.1pt,
    linewidth=0.025,fillstyle=solid,polarangle=\iA,holenumber=5,opacity=0.5](0,0)}
\end{animateinline}
\end{codeblockA}


\begingroup
\psset{unit=0.6cm}
\begin{animateinline}[
  width=0.9\linewidth,
  begin={\begin{pspicture}(-14,-14)(14,14)},
  end={\end{pspicture}},palindrome,controls]{5}
\multiframe{181}{i=0+10}{%
  \psgrid[style=gridstyleA,unit=1.4](-10,-10)(10,10)%
  \ifnum\i=181 \psset{gearwheels=false}\fi
  \psSpirograph[Z1=50,Z2=20,m=0.2,linewidth=0.025,fillstyle=solid,opacity=0.75,
    polarangle=\i,circles,TypeA=false,
    thetamax=\i,curvecolor=red,curvewidth=2pt,HolePos=1.5]}
\end{animateinline}
\endgroup
\psset{unit=1cm}

\begin{codeblockA}[title=Animation example]
\psset{unit=0.6cm}
\begin{animateinline}[
  width=0.9\linewidth,
  begin={\begin{pspicture}(-14,-14)(14,14)},
  end={\end{pspicture}},palindrome,controls]{5}
\multiframe{181}{i=0+10}{%
  \psgrid[style=gridstyleA,unit=1.4](-10,-10)(10,10)%
  \ifnum\i=181 \psset{gearwheels=false}\fi
  \psSpirograph[Z1=50,Z2=20,m=0.2,linewidth=0.025,fillstyle=solid,opacity=0.75,polarangle=\i,circles,TypeA=false,
    thetamax=\i,curvecolor=red,curvewidth=2pt,HolePos=1.5]}
\end{animateinline}
\end{codeblockA}

\clearpage

\section{Connect the two gears with a rubberband}

This is an adaptation with PSTricks of an idea of Alejandro Teutli which he realized with Mathematica:
\url{https://demonstrations.wolfram.com/ParametricMovementOfARubberBand/} which is a  variation of a spirograph.
A rubber band is fixed by its ends on two gears. A pencil tied in the middle of the elastic rubberband draws the curve obtained when the gears are
rotating. The optional argument \Lkeyword{RubberBand} must be used, if you want such a spirograph. It is only available
in 3D.

\setSpirographDefaults

\bigskip
\psset{unit=1cm}
\noindent
\begin{animateinline}[
  begin={\begin{pspicture}(-6,-3)(9,5.5)\psframe*[linecolor=yellow!40](-6,-3)(9,5.5)},
  end={\end{pspicture}},
  palindrome,controls,
%  autoplay
]{5}
  \multiframe{181}{iA=0+4}{%
    \psSpirograph[RubberBand,Z1=20,Z2=40,m=0.2,viewpoint=2 -5 3,
      arrowinset=0,arrowsize=0.2,
      wheelrotation=\iA, opacity=0.5,
	  linewidth=0.025,color1=yellow,color2=blue!50]}
\end{animateinline}


\clearpage
%\begin{LTXexample}[pos=t]
\begin{codeblockA}[title=Example with a rubber band]
\begin{animateinline}[
  begin={\begin{pspicture}(-6,-3)(9,5.5)\psframe*[linecolor=yellow!40](-6,-3)(9,5.5)},
  end={\end{pspicture}},
  palindrome,controls,
%  autoplay
]{5}
  \multiframe{181}{iA=0+4}{%                            2 -5 3
    \psSpirograph[RubberBand,Z1=20,Z2=40,m=0.2,viewpoint=2 -5 3,arrowinset=0,arrowsize=0.2,
      wheelrotation=\iA, opacity=0.5,
	  linewidth=0.025,color1=yellow,color2=blue!50]}
\end{animateinline}
\end{codeblockA}
%\end{LTXexample}


%There are some more examples in the documention directory of the package.

\clearpage

\section{List of all optional arguments for \texttt{pst-spirograph}}

\xkvview{family=pst-spirograph,columns={key,type,default}}


\bgroup
\nocite{*}
\raggedright
\printbibliography
\egroup

\printindex



\end{document} 

