# Koch Curve

A Koch curve is a well-known fractal, first described by a Swedish Mathematician, Helge Von Koch, in his paper "Sur une courbe continue sans tangente, obtenue par une construction géométrique élémentaire".

Put three Koch curves together in a triangular configuration and you have a Koch Snowflake.

Let's build up a Koch curve with Logo. It's a variation on a straight line, so we'll start with just a line. Here's a line.

fd 120

Okay, that is definitely a line. Now let's make a slightly bumpy line.

fd 40 lt 60 fd 40 rt 120 fd 40 lt 60 fd 40

That's all well and good. But looking at the code, I see this 'forward 40' bit is very repetitive. Programmer's hate repetitive code.

Let's make a function that does that for us.

to line :length [fw :length] end line 40 lt 60 line 40 rt 120 line 40 lt 60 line 40

Okay, that didn't achieve very much, but trust me, I'm going somewhere with this. It did demonstrate how we can make a function that accepts parameters.

Now let's neaten it up a little by making a function out of bumpy line. That way we can reason about bumpy-line all on it's own, without having to think about its constituent parts.

to line :length [fw :length] end to bumpyline :length [ line :length lt 60 line :length rt 120 line :length lt 60 line :length ] end bumpyline 40 bumpyline 30 bumpyline 20 bumpyline 10

Bumpyline is very easy to use.

Now get ready for the giant leap.

It's time to turn our bumpy line into a fractal, by exploring the idea of 'self-similarity'. 'Self-similarity' is the idea of making a shape where the entire shape is similar (or exactly the same) to a part of itself.

What if each line in the shape was in fact a bumpy line?

Here's a naive version of that idea. (Hint: this won't actually work).

to bumpyline :length [ bumpyline :length/3 lt 60 bumpyline :length/3 rt 120 bumpyline :length/3 lt 60 bumpyline :length/3 ] end bumpyline 40

The error message says "Too much recursion!". How much recursion do we have? We have an infinite amount. Bumpyline calls bumpyline calls bumpyline on and on for ever.

Sometimes, too much recursion is too much recursion.

How can we limit the amount of recursion?

We can use a technique called 'stack counting'. Each time we call bumpyline we pass in a number. If the number is bigger than a certain limit, we don't call bumpy line, we do something else instead (e.g. draw a straight line instead of a bumpy line).

to bumpyline :length :count ifelse :count > 2 [ fw :length ] [ bumpyline :length/3 :count+1 lt 60 bumpyline :length/3 :count+1 rt 120 bumpyline :length/3 :count+1 lt 60 bumpyline :length/3 :count+1 ] end bumpyline 120 1

And that's a Koch curve in anyone's book.

We could change the limit, so that instead of 'greater than 2' it says 'greater than 3' or 'greater than 5'... But the right way to do it is to encapsulate this information in a parameter. Let's do that.

to bumpyline :length :count :limit ifelse :count > :limit [ fw :length ] [ bumpyline :length/3 :count+1 :limit lt 60 bumpyline :length/3 :count+1 :limit rt 120 bumpyline :length/3 :count+1 :limit lt 60 bumpyline :length/3 :count+1 :limit ] end bumpyline 240 1 5

## Refactoring to create a better program

Now there's a couple of refactorings we can make to improve our code. First up, let's call 'bumpyline' what it really is: a koch curve. Second, we can simplify the way we handle count and limit. Instead of counting up from 1, we can count down from :limit, and stop when we hit zero.

to koch_curve :length :limit ifelse :limit = 0 [ fw :length ] [ koch_curve :length/3 :limit - 1 lt 60 koch_curve :length/3 :limit - 1 rt 120 koch_curve :length/3 :limit -1 lt 60 koch_curve :length/3 :limit - 1 ] end koch_curve 240 5

That's our best Koch curve, but what's a Koch snowflake? Well that's another article altogether. (It builds on this one)

## Alterations

Let's dig into our curve here, and see if we can make some little alterations with surprising results.

Now the fundamental 'self similar' piece in the koch curve, is what we called the "bumpy line".

What if we change it up a bit and alter the shape of the bumpy line.

For example, we can change some of the angles. I'll change one of the 60 degree angles to 61 degrees. What happens to our curve then?

to koch_curve :length :limit ifelse :limit = 0 [ fw :length ] [ koch_curve :length/3 :limit - 1 lt 61 koch_curve :length/3 :limit - 1 rt 120 koch_curve :length/3 :limit -1 lt 60 koch_curve :length/3 :limit - 1 ] end koch_curve 240 1 setxy 20 175 rt 1 koch_curve 240 3 rt 27 setxy 120 300 koch_curve 240 5

The bumpy line is no longer straight. It bends upward. In each image I've increased the `limit`

from 1 to 3, and then up to 5. It goes from 'not quite straight' to 'crooked' to 'completely twisted'. That tiny alteration, just a single degree has destroyed the Koch Curve.

What I've done is broken the 'self-similarity'. The outer bumpy-line no longer resembles the inner bumpy line.

What is the property of the bumpy line that is no longer self-similar? Straightness. I've taken away straight-ness. If we persist in the modifications without restoring self-similarity we'll be able to make some very pretty patterns, but they won't be fractals. I can try to put self-similarity back by adjusting one of the other angles to compensate for the one I changed.

There were originally two 60 degree angles inside the koch kurve. Now I've changed one to 61 and the other to 59, so they still approximate to a straight line.

to koch_curve :length :limit ifelse :limit = 0 [ fw :length ] [ koch_curve :length/3 :limit - 1 lt 61 koch_curve :length/3 :limit - 1 rt 120 koch_curve :length/3 :limit -1 lt 59 koch_curve :length/3 :limit - 1 ] end koch_curve 240 1 setxy 10 190 koch_curve 240 3 setxy 10 290 koch_curve 240 5

Now let's generalize this, by adding a new parameter, `skew`

. Skew is the amount of change we want to add/subtract from our 60 degree angles. And we'll experiment with large amounts of skew.

to koch_curve :length :limit :skew ifelse :limit = 0 [ fw :length ] [ rt :skew/2 koch_curve :length/3 :limit - 1 :skew lt (60 + :skew) koch_curve :length/3 :limit - 1 :skew rt 120 koch_curve :length/3 :limit -1 :skew lt (60 - :skew) koch_curve :length/3 :limit - 1 :skew lt :skew/2 ] end koch_curve 240 1 20 setxy 250 90 koch_curve 240 3 30 setxy 550 90 koch_curve 240 5 50

to koch_curve :length :limit :skew ifelse :limit = 0 [ fw :length ] [ koch_curve :length/3 :limit - 1 :skew lt 60 + :skew koch_curve :length/3 :limit - 1 :skew rt 120 koch_curve :length/3 :limit -1 :skew lt 60 - :skew koch_curve :length/3 :limit - 1 :skew ] end koch_curve 240 3 40 setxy 300 200 koch_curve 240 4 40 setxy 560 200 koch_curve 240 5 40 setxy 820 200 koch_curve 240 6 40

This is still a bit broken. The higher the :limit, the smaller the curve. Why is that?

Here's a different variation. A koch curve is built from 4 straight sections. What if every second section was reversed?

to koch :length :count :limit ifelse :count > :limit [ fw :length ] [ koch :length/3 :count+1 :limit lt 60 pu fd :length/3 rt 180 pd ; i.e. reverse the next segment koch :length/3 :count+1 :limit pu rt 180 fd :length /3 pd; move to the start of the reversed segment rt 120 koch :length/3 :count+1 :limit lt 60 pu fd :length/3 rt 180 pd ; i.e. reverse the next segment koch :length/3 :count+1 :limit pu rt 180 fd :length /3 pd; move to the start of the reversed segment ] end to dot color [255 0 0] circle 2 color [0 0 0] end setxy 55 120 dot koch 240 1 1 setxy 345 120 dot koch 240 1 2 setxy 55 240 dot koch 240 1 3 setxy 345 240 dot koch 240 1 4 setxy 55 360 repeat 3 [ koch 120 1 4 rt 120 ]