I was working with Thomas a few weeks ago in his quest to learn how to create fractal images. He essentially asked the following question: How can you locally change the appearance of a fractal?
For example, consider the well known Koch snowflake (which we discussed earlier on Day007), shown below.
Thomas asked if it might be possible to keep the overall shape of the snowflake, but change the details at the edges. To discuss this possibility, let’s recall the algorithm for producing the snowflake (although this algorithm produces only one-third of the snowflake, so that three copies must be put together for the final image):
sf1(n):
- if n = 0, then draw a line segment, otherwise:
- sf1(n-1); turn -60; sf1(n-1); turn 120; sf1(n-1); turn -60; sf1(n-1)
This is “pseudocode” for drawing part of the snowflake n levels deep. The difficulty is that the segments are drawn only when n = 0. Thomas was wanting something different to happen, say, at level 3 and below in an algorithm which recursed 6 levels deep.
Then it occurred to me — there’s no reason the “otherwise” couldn’t be broken down into further cases: make the recursive call depend on the value n.
But in order to do this, I needed to use a different recursive call. What to use? Well, it happens that by slightly changing the angles in sf1, the snowflake undergoes a rotation by 30 degrees. Here is the pseudocode, along with the image.
sf2(n):
- if n = 0, then draw a line segment, otherwise:
- sf2(n-1); turn 120; sf2(n-1); turn -60; sf2(n-1); turn 120; sf2(n-1)
So how do we combine these fractals? As suggested earlier, break down the original “otherwise” clause. The following algorithm adds a “little” of the second snowflake to the first since the second algorithm is only called when n = 1.
new1(n):
- if n = 0, then draw a line segment, otherwise:
- if n = 1, sf2(n-1); turn 120; sf2(n-1); turn -60; sf2(n-1); turn 120; sf2(n-1)
- else sf1(n-1); turn -60; sf1(n-1); turn 120; sf1(n-1); turn -60; sf1(n-1)
Here is the resulting fractal image (recursing 6 levels):
You can already see a difference. Now let’s try adding a little “more” of the second snowflake by using the second algorithm when n is 1 or 2, as shown below.
new2(n):
- if n = 0, then draw a line segment, otherwise:
- if n <= 2, sf2(n-1); turn 120; sf2(n-1); turn -60; sf2(n-1); turn 120; sf2(n-1)
- else sf1(n-1); turn -60; sf1(n-1); turn 120; sf1(n-1); turn -60; sf1(n-1)
Going one level further — using the second algorithm when n is 1, 2, or 3 — produces the following curve.
One level further yields:
And we’re done, since the next level will in fact give the rotated snowflake sf2(6) (although pieced together a little differently — but the resulting fractal is the same).
Now I’ll leave it up to you. There’s really so much to explore here. Here’s just one example. Adding just one additional call to sf2(n-1) after the last one in the algorithm produces the following image:Amazing, isn’t it? Such a small change results in a very different feel to the final image. And of course once smaller changes are made, there’s no reason to stop. Maybe branch into more than two fractal routines? Or maybe perform sf1 when n is odd, and sf2 when n is even. Or….
The only limitation, it seems, is one’s imagination. Comment if you create something interesing!