LFMP8
Learning From Matt Pearson
In nature fractals are very common. Just take a look at this ostrich fern or matteuccia.
Photo, Jeanne de Bont
The Mandelbrot set within a continuously colored environment. Created by Wolfgang Beyer with the program Ultra Fractal 3
When I am honest I must admit that, in terms of shapes, I have always found them terrible. No matter how well put together mathematically. A fractal is a geometric figure composed of parts that are more or less similar to the figure itself. Sounds complicated in text. But when you see the images it quickly becomes clear.
The term fractal is derived from the Latin word fracture meaning ‘broken’. The word ‘fractal’ was first used in 1975 by Benoît Mandelbrot. A French mathematician whose research built on the work of French mathematician Gaston Maurice Julia. In 1918, in an article in the ‘Journal de mathématiques pures et appliquées’, the latter described the ‘iterative application of rational functions’ (Mémoire sur l‘itération des fonctions rationnelles).
This article described the famous Julia set in terms of operations with complex numbers. The article dealt with the repeated successive application of rational functions of complex numbers. Julia thereby laid the foundation for the theory of fractals. So much for the history.
Fractals have an infinite amount of detail. In some fractals, motifs occur that repeat on an increasingly smaller scale. In geometry, a straight line is one-dimensional, a plane is two-dimensional and a spatial shape is three-dimensional. For fractals, the dimension cannot so easily be specified. In this final publication, we are looking with Matt Pearson at ‘fractal iteration as a way of art’.
Henk Lamers
Please note that all code in this publication refers to Matt Pearson's original code in his publication: Generative Art. A practical guide using Processing.
LFMP_08_01_00
LFMP_08_01_01
LFMP_08_01_02
LFMP_08_01_03
LFMP_08_01_04
We start by setting limits. Otherwise, we quickly fall into the trap of infinite recursion. As a first example, we take the branch of a tree. A tree is also an example of natural fractals.
int NumChildren = 3;
int MaxLevels = 3;
The limitations of NumChildren (maximum number of children) and MaxLevels (maximum number of levels) is in place to prevent the program from looping endlessly.
TheTrunk = new Branch (1, 0, width / 2, 50);
Strangely, the branch of the tree starts at the top of the display window. Bit unusual for a branch. Those usually grow from the ground up.
class Branch {
I used this code unchanged. An instance of a branch object is first created.
void drawMe () { Then a call is sent to drawMe on that object. But this can all be found in Matt Pearson‘s original publication.
background (0);
I made the background black. That way the lines of the branches can be seen more clearly.
stroke (255, 64);
In the drawMe function, I gave the white strokes extra transparency. In doing so, the intersections of lines stand out better.
ellipse (x, y, 8, 8);
Furthermore, I found it interesting to see where the ellipses ended up. So I enlarged those slightly.
TheTrunk = new Branch (1, 0, width / 2, 950); I don‘t want the tree to grow out of the ceiling. So I moved the starting point to the bottom of the display window.
endy = y - 100 - (level * random (100)); Length of the branches (but now starting from the bottom).
endx = x + (level * (random (100) - 50)); I made the randomness slightly less. This makes the overall tree less wide.
int NumChildren = 4;
Increased the number of children. Just to see what the effect would be.
endx = x + (level * (random (200) - 100)); Restricting growth in width a little more.
LFMP_08_01_05
strokeWeight (MaxLevels - level + 32);
Boosted the number of levels (that‘s when a branch splits in two) to 32. But that appears to have no effect. Because MaxLevels is initialised as 3. But MaxLevels is used here to determine the thickness of the line.
ellipse (x, y, 32, 32); The starting points of each level are indicated by an ellipse.
LFMP_08_01_06
strokeWeight (128);
This is much simpler than in the previous program. But a line width of 128 is also over the top.
ellipse (x, y, 64, 64);
The ellipses increase in size with the thickness of the lines.
LFMP_08_01_07
LFMP_08_01_08
LFMP_08_01_09
LFMP_08_01_10
frameRate (1); A new image is now calculated every second.
// noLoop ();
I have commented out noLoop. That means animation of the tree. This allows the mousePressed function to be dropped.
int NumChildren = 5;
int MaxLevels = 5;
Increased the number of children and levels to 5.
endy = y - 100 - (level * random (20)); Random length of branches reduced from 125 to 20. Reducing the tree height.
strokeWeight (2);
Made the line thickness much thinner. The tree does get more branches now and also gets fuller.
// ellipse (x, y, 64, 64); Commented out the ellipses.
int MaxLevels = 4; The number of levels reduced to 4.
stroke (255, 16);
Reduced the transparency of the lines to 16, meaning you have to click several times before a full tree appears.
endy = y - 200 - (level * random (50));
This gives you a greater distance between levels. But because you have to click many times, regularities in the levels also arise. This makes the tree less credible. Trees are always unpredictable in their growth.
LFMP_08_02_00
Animate a tree
LFMP_08_02_01
LFMP_08_02_02
LFMP_08_02_03
LFMP_08_02_04
LFMP_08_02_05
This section deals with the animation of the tree we just created. In itself, it is noteworthy that the centre is now suddenly in the middle of the display window. Which makes it less of a tree.
void draw () {
In fact, I had the draw block earlier in the program. So animation was always possible. I also think we should forget about the idea tree and rather look at a random movable model. I haven‘t changed anything else about this animation. This is the original program published by Matt Pearson in his book.
stroke (255, alph);
Since I am using a black background here, I use white transparent lines.
int NumChildren = 4; int MaxLevels = 6; NumChildren has gone from 16 to 4. MaxLevels has gone from 3 to 6. This gives a little more spatiality. But the white bar in the centre is still a mystery.
int NumChildren = 3; int MaxLevels = 10;
At 10 MaxLevels, we are at the limits of my MacStudio, though. You can no longer call this animation. Each frame takes about half a second to generate.
int NumChildren = 2; int MaxLevels = 7;
With these settings, there is no further delay in the animation.
rect (endx, endy, len / 6, len / 6); Replaced the ellipses with squares.
ellipse (endx, endy, len / 6, len / 6); I have re-introduced the ellipses. In fact, there is much more to get out of this but I‘m too curious to see what‘s in the next part. The first stem or pointer remains completely white. I think it is because the other stems keep growing from that point. But I am not sure about that.
LFMP_08_03_00
Reach the boundaries
LFMP_08_03_01
LFMP_08_03_02
LFMP_08_03_03
LFMP_08_03_04
LFMP_08_03_05
The annoying thing about this program is that you cannot endlessly increment NumChildren and MaxLevels. Although our MacStudio is less than half a year old, it takes almost a second to generate a new image.
int NumChildren = 7; int MaxLevels = 7;
With NumChildren and MaxLevels both at 7, we have reached the maximum achievable with our MacStudio. Even if the file is pulled from our server to the desktop, there is hardly any speed gain.
int NumChildren = 4;
int MaxLevels = 4;
With these settings, the animation runs smoothly again.
background (0);
As usual, I changed the background to black.
len = (1 / level) * random (100); Random (500) has been replaced by random (100).
lenChange = random (2); rotChange = random (2); Both functions changed from random (10) - 5 to random (2).
if (level < MaxLevels) {
The parts of the tree now physically move independently of each other. They are divided into groups of four trunks and ellipses.
int NumChildren = 5;
The groups now consist of five trunks and ellipses.
strokeW = (4);
This determines the thickness of the lines and ellipses.
len = (2 * random (2));
Determines the radius of the animation. Suppose you would take random (200) then the length of the trunks would extend beyond the display window.
int NumChildren = 10;
int MaxLevels = 4;
It seems that NumChildren can be raised quite a bit higher than MaxLevels. This animation is still running flawlessly.
line (y, x, endy, endx);
The lines forming the trunks now rotate seemingly independently of the ellipses. y, x, endy and endx are interchanged.
ellipse (endx, endy, len / 12, len / 12); Endx and endy form the centres for the ellipses. So there is indeed some dependence of the trunks.
ellipse (endx, endy, len / 4, len / 4); The ellipses are now a third larger and filled.
point (x, y);
The point function makes it appear that ellipses are filled. That‘s really the only difference from the previous version.
LFMP_08_04_00
The Sutcliffe pentagon
To understand the Sutcliffe pentagon, I had to go through its logic step by step. Because according to Alan Sutcliffe, there is something special about the pentagon. First, determine the centres of the five sides. Then draw a line perpendicular to the centre at each of these points. Connect the ends of those lines until they make a new pentagon. Again, the remaining area of that shape can be subdivided into other pentagons. That means that within each pentagon there are six sub-f pentagons. And within each of those six sub-f pentagons, this is repeatable to infinity. So basically, this should also be possible with triangles, squares and circles.
The way Matt Pearson draws a pentagon is very clarifying. You don‘t draw five lines between five points. But he creates a method that is slightly more general. You rotate 360 degrees around a centre point. And you extrapolate points at certain angles. If you then plot a point every sixty degrees, for example. Then you get a hexagon. If you plot a point every 72 degrees, you get a pentagon.
pentagon = new FractalRoot(); Creates root pentagon.
pentagon.drawShape (); Calls drawShape method on it.
Branch (int lev, int n, PointObj []points) { Constructs Branch object
for (int i = 0; i < outerPoints.length; i++) { Draw outer shape, branch draws itself.
class PointObj {
Object class to store an x, y position. These are the comments from Matt Pearson‘s program. I have only tried to understand it as best as I could.
LFMP_08_04_01
LFMP_08_05_00
LFMP_08_06_00
LFMP_08_06_01
LFMP_08_06_02
LFMP_08_06_03
LFMP_08_07_00
LFMP_08_07_01
The same program but with a black background and white lines.
Plot the centres on each side of the pentagon.
float StrutFactor = 0.2; Variable that determines how far the inner dots are placed. This, of course, also applies to the inner pentagon.
Here, I am still following the code created by Matt Pearson. I have only changed something about the shape.
strokeWeight (0.005); Looking for the limit of the visual by using as thin lines as possible.
This version is almost identical to Matt Pearson‘s version as shown on page 172.
int MaxLevels = 4;
The number of MaxLevels was kept as low as possible because otherwise the animation runs too slow.
StrutNoise += 0.01; The higher the number in StrutNoise is the higher the frequency of the object's size.
StrutFactor = noise (StrutNoise) * 2; Probably the multiplier is a little too large, making the animation rather jerky.
LFMP_08_07_02
LFMP_08_07_03
LFMP_08_08_00
LFMP_08_08_01
LFMP_08_08_02
LFMP_08_08_03
LFMP_08_08_04
ellipse (midPoints [j].x, midPoints [j].y, 128, 128); The ellipses of the centres enlarged. Omitted the outlines.
ellipse (projPoints [j].x, projPoints [j].y, 32, 32); Project points doubled in size.
// line (midPoints [j].x, midPoints [j].y, projPoints [j].x, projPoints [j].y); Commented out all the lines.
Commented out all the ellipses. I only work with lines now. The lines and ellipses are now back. But there are times when the lines can no longer be seen and only project and centres remain.
The strange thing in this program is that the outerPoints are not displayed while the calculation for them is done. Other than that, I don‘t see much difference from the previous program.
int _numSides = 7;
The number of sides has been increased from 4 to 7, leading to an interesting shape that is not symmetrical. All lines are commente out. But when changing numSides from 4 to 5, 6 and 7, huge differences in the shape take place.
int _numSides = 16;
This setting leads to a delay in the animation. And because the number of sides is so large, you experience rather a circle-like movement and shape. This is also immediately the last version I made. I feel I could have got a lot more out of it. But at some point you have to put a stop to it. Otherwise, your workflow will also keep spinning in circles. And that brings us to the end of these eight publications.