Manjushra wrote a little Curly Logo program to draw a heart shape, which got me thinking about heart shapes in general.
A heart shape has a cuspy bit at the top. How might we draw that in Logo?
Consider the following Logo program:
repeat 180 [ fd something lt 1 ]
Where something might be a variable quantity, or it might be a constant. Observe that if something is a constant, 1 say, then the program draws part of a circle (a half-circle in fact). Consider what happens if something varies a bit at each step, what can we say about the shape?
Well, consider the direction that the turtle faces, its heading. Because
fd something does not turn the turtle, but
lt 1 does, we can say that will start somewhere (home, say), end up somewhere else, and will be facing in the opposite direction. In between where it started and where it ended up will be some sort of curve. So something could be any function of repcount, which goes from 1 to 180, and you get some sort of curve.
What if the function starts positive and ends up negative? Well, first you need to know that fd -x moves the turtle backward by x steps. But it doesn’t turn the turtle round, the turtle stays facing exactly the same way. So imagine what the turtle does as the something decreases, passes through 0, then becomes negative. As something decreases the turtle will take smaller and smaller steps, but each step will turn the same amount. As it get very close to 0 it will be almost turning on the spot; the effect is that the curve gets tighter and tighter (increasing curvature). When something is 0 the turtle will turn on the spot, and as something goes negative the turtle will continue turning in the same direction, but will now step backwards. The result is that we get a pinched curve, or cusp:
cs lt 90 repeat 180 [ fd 2 - repcount / 45 lt 1 ]
Notice that the turtle is now pointing to the right and has drawn the last part of the line (the left hand half) by moving backwards.
That cusp looks just right for the top of a heart shape.
So here’s a plan for drawing a heart shape:
fd something lt 1, where something starts positive and decreases
fd something lt 1, with something going from 0 to some negative number.
The turtle’s total turn will be 540, so our loop will look like:
repeat 540 [ fd something lt 1 ] . something needs to start at some positive value, go to 0 when the turtle is facing south (repcount = 270), and then go to some negative value. “(270 – repcount) * scale” would do. Bracketed expressions are kind of embarrassing in Curly Logo at the moment (you have to use Lisp syntax), and it can take a while to do 540 steps, so let’s do 54 steps turning 10 each time (so we still have a total turn of 540):
cs pu bk 100 rt 90 pd repeat 54 [ fd 27 - repcount lt 10 ]
This looks pretty good but has a couple of easily fixable problems. One “leg” is longer than the other, that’s because one of the steps forward that we take is 0. repcount starts from 1 so we take 26 steps forward, one 0 step, and 27 backward (negative step). If we use “27.5 – repcount” instead then we’ll have 27 forward steps and 27 backward steps, and they’ll balance. The other problem is that the starting off line is at a slightly different angle than the finishing line, resulting in the whole heart being tipped to the right slightly. This is a very common problem in logo drawings (consider: repeat 18 [ fd 20 rt 20 ] draws an approximate circle, but the centre of the circle is not directly to the turtle’s right), and there are 2 solutions. Either split the forward into 2 parts and go [ fd x lt y fd x ] or split the turn into 2 parts and go [ lt y fd x lt y ]. In our case it’s easier to split the turn into 2:
ht cs pu bk 100 rt 90 pd repeat 54 [ lt 5 fd 27.5 - repcount lt 5 ]
Sweet. The crossed legs at the bottom is the problem that’s not so easy to fix.
So our something function in this case is a straight line that goes from +26.5 to -26.5. Note that the scale of the function doesn’t matter. If the function was a straight line from +10 to -10 it would still draw the same shape, just smaller. So a straight line function didn’t quite work, what other functions do we know?
We need a function that crosses 0 once, and that has a graph that has rotational symmetry about the point where it crosses 0. How about cosine? (see the cosine graph (black) on the Curly Logo Gallery) Of course,
cos x crosses 0 when x is 90, and we want a function that crosses 0 when x is 270, but that’s a simple matter of replacing x with x/3.
So the Logo code would be something like:
repeat 540 [ fd cos repcount / 3 lt 1 ]
It turns out to be a little neater to make 180 turns of 3 rather than 540 turns of 1:
repeat 180 [ fd cos repcount lt 3 ]
Cute. And happily this heart shape is joined up, it finishes exactly where it starts. I didn’t plan that.
Here’s a nice generalisation to play with:
to rose n s l repeat 360 * n [ fd l * cos repcount lt s ] end
n is how many complete periods of cosine should be used. s governs the speed at which the turtle turns, in total the turtle will perform n × s full revolutions of the circle. l is a linear scaling factor, it just makes the drawing bigger or smaller.
rose .5 3 4 gives (a bigger version of) the cardioid we just drew.
rose 2 2.5 4 gives a lovely 4-fold mandala thingy (it was this discovery that made me call the function rose). Hint: it helps if n × s is an integer, or sometimes, half of an integer. Have fun!