After pressing the ‘new random worlds’ button in Chaotica one too many times, I decided it was time to bring some structure to the chaos game. Chaotica makes it surprisingly easy to create stunning fractals, even without fully understanding the underlying mathematics. Stephen Wolfram believes the best way to spark scientific curiosity in children is to let them explore the results first, and dive into the theory later. Inspired by this approach, here’s an implementation you can experiment with right away!
A | B | C | D | E | F | P |
---|---|---|---|---|---|---|
Post affine | ||||||
The implementation above, written in JavaScript, is quite limited in terms of shading (none). For those interested in exploring the more advanced features of Chaotica, I’ve included a GitHub repository containing a Python script that converts IFS to Chaotica parameters. You can either dive into the code to understand its workings or experiment with parameters directly in Chaotica’s world editor. For those unfamiliar, Chaotica is free (with some minor limitations) and available for Linux, macOS, and Windows and can be downloaded here. Before proceeding, this article assumes a basic understanding of Chaotica, but the manual is an excellent resource for beginners.
Iterated function systems
Chaotica uses something called an Iterated Function System (IFS). The Wikipedia I have linked here is quite useless if you're not familiar with mathematical notation. I would often give up understanding something when all searches ended up in needlessly complicated explanation, so will keep it simple and start with an example.
\[F_0(x,y)=(\frac{x}{2},\frac{y}{2})\]
\[F_1(x,y)=(\frac{x+1}{2}, \frac{y}{2})\]
\[F_2(x,y)=(\frac{x}{2},\frac{y+1}{2})\]
To play the chaos game you need functions, a pen, graphing paper, and a die. For this particular example, I will use the functions above this paragraph. These three functions each take Cartesian XY coordinates as input and output new Cartesian XY coordinates. Feel free to experiment with a different set of functions, but note that each function must take and return a set of Cartesian XY coordinates. Now follow these steps:
- Draw a large square on your graphing paper
- Blindfold yourself, you can use duct tape if you don't have a blindfold
- Take your pen and place a dot within the square drawn in step 1. This may take multiple attempts. Take your time
- The dot from step 3 are your initial Cartesian XY coordinates. The square is a so-called bi-unit square. The bottom-left has coordinates (0,0), top-right (1,1) and the middle (0.5, 0.5)
- Roll your die and observe the outcome
- f you rolled a one or a two pick function $F_0$. Pick $F_1$ if you rolled a three or a four, and $F_2$ otherwise
- If this is your first time at step 7 input the coordinates from step 4 into the function picked at step 6, otherwise input the coordinates that resulted from the last time you visited this step. Note down the output from this step
- Place a dot at the coordinates you noted down in step 7 and go back to step 5, unless you are bored, then you are allowed to stop
Congratulations! You just played the chaos game. If everything went right, you will have ended up with something like the image below: the Sierpiński gasket. If you didn't, just repeat the process a few thousand times. If that takes too long: don't worry, computers don't fudge numbers and they love doing repetitive stuff and they also love doing repetitive stuff.
The particularly astute may have noticed that the first few dots don't exactly align with the Sierpiński gasket. In the paper 'The Fractal Flame Algorithm' by Draves et al. the pseudocode for the algorithm skips plotting the first 20 iterations. This would likely dissuade people from trying so I left it out.
Many fractals on this page use a set of affine transformations and have an accompanying table of values.
\[F_n(x,y)=(ax + by + e, cx + dy + f)\]
a | b | c | d | e | f | p | |
$F_0$ | 0.0 | 0.0 | 0.0 | 0.16 | 0.0 | 0.0 | 0.01 |
$F_1$ | 0.2 | -0.26 | 0.23 | 0.22 | 0.0 | 1.6 | 0.07 |
$F_2$ | -0.15 | 0.28 | 0.26 | 0.24 | 0.0 | 0.44 | 0.07 |
$F_3$ | 0.85 | 0.04 | -0.04 | 0.85 | 0.0 | 1.6 | 0.85 |
nstead of equiprobable odds of choosing a function, this particular flame fractal has a p that indicates the probability that the function is chosen from the set. Translating this to Chaotica gives us the famed Barnsley Fern. Note that this render looks slimmer than the render of the Wikipedia page, because the Wikipedia canvas is scaled. This brings me to another topic. The curious might have tried entering the values from the table above in the small renderer I wrote. Only a few dots likely showed up. That's because this transforms from the table apply to a different scale and translation. By translating and scaling during the render step the fractal should show up as it's supposed to. These are called post-transforms and can be seen as transforms applied to the entire fractal. Try feeding the last row beneath the renderer the following values: 0.09, 0, 0, 0.09, 0.5 and 0.9 respectively. There is no p, because this transformation is always applied!
Chaotica
How do we translate an IFS to Chaotica? Let's first dissect what an affine transformation does. An affine transformation scales, translates and rotates vectors. In this particular case, we're interested in manipulating 2D-vectors or pixel coordinates. We've seen these operations in the tables above. Chaotica also uses these types of operations.
To see what an operation does calculate the outcome operation applied on the vectors of the unit square ([0,0], [0,1], [1,0], [1,1]). Chaotica uses lengths angles and offsets which you can calculate using the original unit squares with the transformed vectors. I advise you to draw these and brush up on your high school geometry homework.
For each function in the system add a new iterator in the world editor. For each iterator add a new transform. The new transform will automatically be a linear transformation, exactly what we need. Now in the flam3 transform dropdown select 'pre affine'. Here you can change the scale, translation, and rotation. Now change the weights to reflect the probabilities from the table. The base weight can remain unchanged.
If you did things right you will see a fractal render on the main screen. But the astute will notice that the fractal seems inverted and upside down. For some inexplicable reason Chaotica the Y-axis angle is the angle between the original angle and the vector [0,1] + 90 degrees. To make it easy I have made a Python script that will do all these operations for you.
The inverse problem
The title of this blog wasn't clickbait. I will now show you how to do the inverse, i.e. find the functions that lead to the desired flame fractal (text in this case). There are in my opinion two tractable ways of doing it: the hard way at your expense or the hard way at a computer's expense. There is no easy way. The former is just manual trial and error by translating, rotating, and scaling affine transform functions with some intelligent guesses, and the latter automated trial and error in the form of an evolutionary algorithm.
Although it is hard to find functions for your specific text, it doesn't mean you need to reinvent the wheel. Learning from examples and then modifying them is a much easier way. A quick Google search leads you to the excellent IFS page of Paul Bourke that contains the functions to create the 'Chaos' fractal flame (it also has the weights for the Barnsley Fern).
One important clue is the number of segments. The word CHAOS has 19 segments in total when written in a font like the one you'll find on a digital clock. To start you off, find out how many segments you need, and then fill each row in the p column with the reciprocal of the number you find (e.g. 1/19 for the word chaos). Try finding which segment belongs to which and perhaps remove the C or S. Removing the begin or end letter reveals that each segment is scaled so that it exactly fits the segment. I recommend finding segments similar to the ones you need and then in- or decrease a value and see what it does. Use this technique to position your segments as you please. Once you have found your text fractal you can apply all sorts of operations to them, like below.
(2022 edit) Here's a Turtletoy I coded
This blog is a work in progress. Hope you enjoyed it nevertheless! If something is unclear or if you have some critique please let me know at matigekunstintelligentie@gmail.com
[latexpage]