CXT105@psuvm.psu.edu (Christopher Tate) (10/26/90)
Quite a few people have asked me for my code to draw Spirograph(tm) pictures, so here it is. I'm afraid I have to clear up a mistaken impression I gave in my original post: the Spirograph(tm) code only draws black-and-white, not color. However, it will soon, so when that's ready, I'll post the pertinent changes (or the original, depending on how I feel :-). For anyone not familiar with Spirograph (gasp!), the concept is that the picture is drawn by putting a pen through a hole in a small toothed disk, at some (variable) distance from the center of the disk, and then rolling the disk around the inside of a toothed ring whose inner radius is greater than the radius of the disk. You with me so far? In mathematical talk, this translates to a curve called a "cycloid," which is a class of curves defined by rolling a disk around something, and watching what a particular point on the disk does. The curves are usually expressed parametrically; the equations for true Spirograph pictures are as follows: x = (R - r) * cos(theta) + a * cos(phi) y = (R - r) * sin(theta) + a * sin(phi) where R, r, and a are the ring diameter, the disk diameter, and the distance from the center of the disk to the pen, respectively. Theta is the main parameter of angle around the circle; it starts at zero and increases. The picture starts repeating when 2 * pi * r theta = ------------ gcd(R, r) so this is used as the limit on theta when actually drawing the picture. Phi is a function of theta, it is the rotational position of the disk at any given point, and is calculated by (R - r) phi = --------- * theta r (Sorry for all the math, but this really is a complex class of curves, and it took me some time to figure out the relation between phi and theta. Of course, this probably shows that Math is the wrong major for me, but oh, well.... Now you can impress your enemies and frighten your friends by knowing the parametric equations for Spirograph!) This process generates finite curves because the ratio of the radii of the ring and the disk is a rational number. In the real Spirograph, there are several different disks to choose from, with holes at various places inside them, and a couple of rings of different diameters. In my program, the user specifies the radius of the disk (called littleR in the code), the radius of the ring (called bigR), and the distance that the "pen" is placed from the center of the disk. Unlike the "analog" version of Spirograph, in my version you can have the pen sitting somewhere off the disk.... :) So, here's the code. I'll post a color version as soon as I have one -- the idea I have right now is to gradually change the pen color as the picture develops. Should be pretty impressive! (As an added bonus, the program contains a well-behaved procedure for calculating the Greatest Common Divisor of two integers. The procedure creates and disposes of its own temporary dictionary, to avoid trashing any existing variables, and runs very quickly.) ------- Christopher Tate | Mercy (noun): | The infrequent art of turning Bitnet: cxt105@psuvm | thumbs-up on your opponent at Uucp: ...!psuvax1!psuvm.bitnet!cxt105 | the end of your rapier. ------------------------------- Cut Here ---------------------------- %!PS-Adobe-1.0 % This program generates a Spirograph(tm) image centered on the page % according to the three parameters bigR, littleR, and a. Images are % generated by calculating successive positions of the cycloid generated % by rolling a small disk inside a larger ring, with a "pen" placed some % distance from the center of the disk. % % bigR is the radius of the "outer" circle (the ring, in Spirograph(tm)) % littleR is the radius of the "inner" circle (the disk) % a is the distance of the "pen" from the center of the inner circle. % % Since the program calculates the total angle through which to % parameterize (i.e. how long it has to roll the disk around in the % ring) by looking for a greatest common divisor, the values of the % parameters bigR, littleR, and a MUST be integers. % % If you're interested, the parametric equations which describe a % Spirograph(tm) image are given by: % % x = (R - r) * cos(theta) + a * cos(phi) % y = (R - r) * sin(theta) + a * sin(phi), % % where phi = ((R - r) / r) * theta. % % This program was written by Christopher Tate, and is hereby placed % into the public domain. Anyone may freely borrow from or modify % this program without permission. Have fun! /bigR 200 def % just change these to define a new image /littleR 81 def % littleR should be less than bigR /a 120 def % a need not be smaller than littleR % Euclid's Greatest Common Divisor algorithm to find gcd(m, n) % Calling process: m n *gcd* result /gcd { 3 dict begin % isolate these variables from the rest of the program /m exch def /n exch def /r m n mod def { r 0 eq {exit} if % quit when r equals zero /m n def /n r def /r m n mod def } loop n % put result on the stack end % restore the original dictionary context } def clippath pathbbox % find the bounding box of the page /ury exch def % remember Upper Right y /urx exch def % remember URx /lly exch def % remember LLy /llx exch def % remember LLx urx llx sub 2 div llx add ury lly sub 2 div lly add translate % move the origin to the center of the page /diff bigR littleR sub def % diff = R - r /frac 1.0 bigR littleR div sub def % frac = 1.0 - (R/r) .08 setlinewidth % sufficiently thin lines newpath diff a add 0 moveto % set initial position /limit 360 littleR mul bigR littleR gcd div def % how far we need to go 0 3 limit % this is the main loop { dup frac mul /phi exch def % calculate phi /theta exch def % recalculate theta theta cos diff mul phi cos a mul add % this is x theta sin diff mul phi sin a mul add % this is y 2 copy lineto stroke moveto % same as x y lineto stroke x y moveto } for showpage