Hello everyone I hope you had a great week! Mine was too short due to the Independence Day (4th of July) holiday here in the U.S. and to make it worse , FULL of frustrating bug fixes so I am going to keep this weeks tutorial short & simple! 😛

Alright, so this week I have a fun math + animation project for you.

We are going to generate a series of images containing the Sierpinski triangle (a well known fractal) and then animate them using the GIFEncoder class released by László Zsid

### The Sierpinski Triangle

Here is a time laps gif of  The Sierpinski Triangle:

Many people (myself included) find fractals incredibly beautiful!

### How does this work?

It’s surprisingly simple to create the Sierpinski Triangle and there are many different ways to accomplish our goal however a really simple way is called the “chaos game“, here is the formula :

1. Select 3 points in the image to form a triangle (ideally it should be an equilateral triangle however based on my experimentation it doesn’t seem to be absolutely required, the triangle will deform (warp) but not entirely disappear).
2. Randomly select any point inside the points.
3. Randomly select any one of the 3 vertex points.
4. Move half the distance from your current position to the selected vertex.
5. Plot the current position.
6. Repeat from step 3.

Once we have created all the images and buffered them we create and write the animation to the new gif.

Here is the code for your review:

<?php

include('GIFEncoder.class.php'); // GIFEncoder class

// Buffer Images
// http://php.net/manual/en/function.ob-start.php
// http://php.net/manual/en/function.imagegif.php
// http://php.net/manual/en/function.ob-get-contents.php
// http://php.net/manual/en/function.ob-end-clean.php
function EncodeImage(\$image, \$delay){

global \$images, \$buffered;

ob_start(); // Start the buffer
imagegif(\$image); // Output image buffer as a gif encoded still
\$images[]=ob_get_contents(); // add the gif still to the images array
\$buffered[]=\$delay; // Delay in the animation.
ob_end_clean(); // Stop the buffer
}

// Build the triangle fractal
// https://en.wikipedia.org/wiki/Sierpinski_triangle
// http://php.net/manual/en/function.imagecolorallocate.php
// http://php.net/manual/en/function.mt-rand.php
// http://php.net/manual/en/function.imagesetpixel.php
function ChaosGame(\$image, \$points){
global \$density,\$x, \$y;

\$counter = 0;
for (\$i = 1; \$i < \$density; \$i++) { // Higher density will plot more points

\$COL = imagecolorallocate(\$image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); // Random Color
imagesetpixel(\$image, round(\$x),round(\$y), \$COL); // Plot the current position
\$a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration

// Move half the distance from your current position
// to the selected vertex for next the iteration
\$x = (\$x + \$points[\$a]['x']) / 2;
\$y = (\$y + \$points[\$a]['y']) / 2;

\$counter++;

if(\$counter >= 1000){
imagepng(\$image , "\$i.png"); // Save the image
EncodeImage(\$image, 1); // Buffer image
\$counter = 0;
}
}

}

\$images;
\$buffered;

\$density = 100000;

\$x = 600; // Reset \$x
\$y = 600; // Reset \$y

\$inset = 10;
\$points[0] = array('x' => \$x / 2, 'y' =>  \$inset); // Top
\$points[1] = array('x' =>   \$inset, 'y' => \$y - 0); // Left
\$points[2] = array('x' => \$x - \$inset, 'y' => \$y - 0); // Right
\$image = imagecreatetruecolor(\$x, \$y); // Create the image resource
ChaosGame(\$image, \$points); // This triangle will rotate
imagedestroy(\$image); // Free memory

// Generate the animation
\$gif = new GIFEncoder(\$images,\$buffered,0,0,0,0,0,'bin');

// Save the gif
\$animation_file = fopen('timelaps.gif', 'w');
fwrite(\$animation_file, \$gif->GetAnimation());
fclose(\$animation_file);

?>

We can have a little more fun by drawing more than one at a time and animating it like this:

Here is the code:

<?php

include('GIFEncoder.class.php'); // GIFEncoder class

// Buffer Images
// http://php.net/manual/en/function.ob-start.php
// http://php.net/manual/en/function.imagegif.php
// http://php.net/manual/en/function.ob-get-contents.php
// http://php.net/manual/en/function.ob-end-clean.php
function EncodeImage(\$image, \$delay){

global \$images, \$buffered;

ob_start(); // Start the buffer
imagegif(\$image); // Output image buffer as a gif encoded still
\$images[]=ob_get_contents(); // add the gif still to the images array
\$buffered[]=\$delay; // Delay in the animation.
ob_end_clean(); // Stop the buffer
}

// Build the triangle fractal
// https://en.wikipedia.org/wiki/Sierpinski_triangle
// http://php.net/manual/en/function.imagecolorallocate.php
// http://php.net/manual/en/function.mt-rand.php
// http://php.net/manual/en/function.imagesetpixel.php
function ChaosGame(\$image, \$points){
global \$density,\$x, \$y;

for (\$i = 1; \$i < \$density; \$i++) { // Higher density will plot more points
\$COL = imagecolorallocate(\$image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); // Random Color
imagesetpixel(\$image, round(\$x),round(\$y), \$COL); // Plot the current position
\$a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration

// Move half the distance from your current position
// to the selected vertex for next the iteration
\$x = (\$x + \$points[\$a]['x']) / 2;
\$y = (\$y + \$points[\$a]['y']) / 2;
}

}

\$images;
\$buffered;

\$density = 100000;
\$frame_increment = 7; // Set to 1 for 360 still images.
// At 7 we get 52.

// Create the still images
for (\$k = 1; \$k < 360; \$k+=\$frame_increment) {
\$x = 600; // Reset \$x
\$y = 600; // Reset \$y
\$points[0] = array('x' => \$x / 2, 'y' =>  0); // Top
\$points[1] = array('x' =>   10, 'y' => \$y - 0); // Left
\$points[2] = array('x' => \$x - 10, 'y' => \$y - 0); // Right
\$image = imagecreatetruecolor(\$x, \$y); // Create the image resource
ChaosGame(\$image, \$points); // This triangle will rotate
\$image = imagerotate(\$image, \$k, 0); // Perform rotation
ChaosGame(\$image, \$points); // This triangle will not
imagepng(\$image , "\$k.png"); // Save the image
EncodeImage(\$image, 1); // Buffer image
imagedestroy(\$image); // Free memory
}

// Generate the animation
\$gif = new GIFEncoder(\$images,\$buffered,0,0,0,0,0,'bin');

// Save the gif
\$animation_file = fopen('Sierpinski_triangle.gif', 'w');
fwrite(\$animation_file, \$gif->GetAnimation());
fclose(\$animation_file);

?>

And as previously mentioned, since this post falls during the week of American Independence I would be remiss by not mixing in a little little Red White and Blue, rendered for your desktop wallpaper pleasure (click to get it fullsize):

Here is the code:

<?php
set_time_limit(300); // 5 Minutes Adjust as needed
ini_set('memory_limit', '2G'); // 2 GB Adjust as needed

\$images;
\$buffered;

\$density = 1000000; // Higher density will plot more points but is costly on large images
\$x = 4000; // Reset \$x
\$y = 4000; // Reset \$y

\$inset = 10;
\$points[0] = array('x' => \$x / 2, 'y' =>  \$inset); // Top
\$points[1] = array('x' =>   \$inset, 'y' => \$y - 0); // Left
\$points[2] = array('x' => \$x - \$inset, 'y' => \$y - 0); // Right
\$image = imagecreatetruecolor(\$x, \$y); // Create the image resource

\$red = imagecolorallocate(\$image, 255, 0, 0);
\$white = imagecolorallocate(\$image, 255, 255, 255);
\$blue = imagecolorallocate(\$image, 0, 0, 255);

for (\$i = 1; \$i < \$density; \$i++) { // Higher density will plot more points but is costly on large images

if(\$x < 4000 / 3){\$color = \$red;}
elseif(\$x > ((4000 / 3)) && \$x < ((4000 / 3)*2) ){\$color = \$white;}
else{\$color = \$blue;}

imagesetpixel(\$image, round(\$x),round(\$y), \$color); // Plot the current position
\$a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration

// Move half the distance from your current position
// to the selected vertex for next the iteration
\$x = (\$x + \$points[\$a]['x']) / 2;
\$y = (\$y + \$points[\$a]['y']) / 2;
}

imagejpeg(\$image , "redgreenblue.jpg"); // Save the image

imagedestroy(\$image); // Free memory

?>

If you would like to obtain a copy of this code from GitHub you can find it here: SierpinskiTriangle Project on GitHub

Please support me on Patreon so I can continue to bring you more great tutorials like this!

As always I hope you found this both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy