Chapter 1 - Turtle Graphics
1 Setup
The following is essentially a Jupyter notebook with a haskell kernel. We will start by turning on some GHC extension, and ihaskell options. The svg files don't work well with my publishing setup.
:extension NoMonomorphismRestriction FlexibleContexts TypeFamilies :opt svg :opt no-lint
1.1 Imports
We will need the turtle drawing package, as well as the Cairo backend for saving the images.
import Diagrams.Backend.Cairo import Diagrams.TwoD.Path.Turtle import Control.Monad
1.2 Helper Functions
The original turtle geometry is done in degrees; however, once one has learned enough math, radians are usually preferred. After teaching Trigonometry several times I have found many people struggle with \(2\pi\) radians in a circle. So I think the easiest way is via "turns" of a circle. Using turns, we have
\begin{equation*} 1 \textrm{ turn } = \tau = 2\pi = 360^\circ. \end{equation*}For me this is the most intuitive, see https://tauday.com/tau-manifesto for more information about \(\tau\).
Functions which convert from degrees or from a turn.
tau = 2*pi fromDeg d = d/360 fromTurn t = t*360
Some short hand functions. The names should be self-explanatory:
ltD/left d
turns left \(d\) degreesrtD/right d
turns right \(d\) degreesfd/forward n
moves the turtle forward a distance \(n\)bk/backward n
moves the turtle backward a distance \(n\)turn t
turn the positive direction (counter clockwise) \(\tau\) turnslt/left t
turn left \(\tau\) turnsrt/right t
turn right \(\tau\) turnspu
pick the pen up, no path will be drawn for commands following one of these commands, that is until the pen is put back downpd/penDown
puts the pen down, a path will be drawn until the pen is pick updrawTDia
draws the turtle diagram in the Jupyter notebook
ltD = left rtD = right fd = forward bk = backward turn = left . fromTurn lt = turn rt = turn . negate pu = penUp pd = penDown drawTDia = diagram . drawTurtle
2 Turtle Drawings
2.1 Basic Shapes
Let start with a square and a triangle of side length \(n\).
square n = replicateM 4 (fd n >> lt (1/4)) triangle n = replicateM 3 (fd n >> lt (1/3))
Now lets draw them
drawTDia $ square 100
drawTDia $ triangle 100
2.2 Simple Composite Drawings
Lets draw a house, composed of drawing a square under a triangle.
house n = do square n pu lt (1/4) fd n rt (1/4) pd triangle n
drawTDia $ house 100
2.3 More Complex Figures
We will define a basic doodle, and then replicate that in various ways doodle, which we will call a re-do-odle.
doodle = do fd 100 rt (1/4) fd 100 rt (1/4) fd 50 rt (1/4) fd 50 rt (1/4) fd 100 rt (1/4) fd 25 rt (1/4) fd 25 rt (1/4) fd 50
drawTDia doodle
redoodle4 = replicateM 4 doodle drawTDia redoodle4
redoodle9 = replicateM 9 (doodle >> rt (1/36) >> fd 50) drawTDia redoodle9
redoodle15 = replicateM 15 (doodle >> lt (1/8) >> fd 100) drawTDia redoodle15
2.4 Circles and Arcs
Next we define how to draw arcs, and circles (actually a regular 1000-gon of side length \(s\)).
circSides = 1000 arc s t = replicateM n (fd s >> turn (t'/circSides)) where n = round ((abs t)*circSides) t' = t/(abs t) circle s = arc s 1
circles s n = replicateM n (circle s >> turn (1/ fromIntegral n)) drawTDia $ circles 1 9
petal s = replicateM 2 (arc s (1/6) >> turn (1/3)) flower s = replicateM 6 (petal s >> turn (1/6)) drawTDia $ flower 1
ray s = replicateM 2 (arc s (1/4) >> arc s (-1/4)) sun s = replicateM 9 (ray s >> turn (4/9)) drawTDia $ sun 1
2.5 Polygons and Friends
The polygon
function draws a regular $n$-gon. The poly
and newpoly
draw other types of polygons.
polygon sides len = replicateM sides (fd len >> turn (1/s)) where s = fromIntegral sides poly len t = replicateM 1000 (fd len >> lt t) newpoly len t = replicateM 10 (fd len >> lt t >> fd len >> lt (2*t))
We can reproduce all the examples in the book.
import qualified Diagrams.Prelude as D
diagram $ D.hsep 0.2 (map drawTurtle [poly 1 (fromDeg 72), poly 1 (fromDeg 60)])
diagram $ D.hsep 0.2 (map drawTurtle [poly 1 (fromDeg 144), poly 1 (fromDeg 135), poly 1 (fromDeg 108)])
diagram $ D.hsep 0.2 (map drawTurtle [newpoly 1 (fromDeg 144), newpoly 1 (fromDeg 135), newpoly 1 (fromDeg 108)])
2.6 Recursion
polySpiral 1 t = fd 1 >> lt t polySpiral n t = fd n >> lt t >> polySpiral (n-1) t
drawTDia $ polySpiral 70 (fromDeg 95)
drawTDia $ polySpiral 70 (1/4)
drawTDia $ polySpiral 70 (1/3)
drawTDia $ polySpiral 70 (fromDeg 117)
polySpiral' l t = fd l >> lt t >> polySpiral (l+1) t
3 Exercises
3.1 Spiral Dots
dot = do pd fd 1 bk 1 pu spiDot 1 t = fd 1 >> dot >> lt 1 spiDot n t = pu >> fd n >> dot >> lt t >> spiDot (n-1) t
drawTDia $ spiDot 70 (fromDeg 95)
drawTDia $ spiDot 70 (1/4)
drawTDia $ spiDot 70 (fromDeg 43)