Creating fractals in MQL5 using the Iterated Function Systems (IFS) – EA MetaTrader 5

Introduction

There are many programs, allowing the creation of self-similar sets, defined by Iterated Function System (IFS). See, for example, Fractint, Fractal Designer or IFS Matlab Generator. Thanks to the speed of MQL5 language and possibility of working with graphic objects, these beautiful sets can be studied in MetaTrader 5 client terminal.

The cIntBMP library, developed by Dmitry (Integer) provides new graphic opportunities and greatly simplifies the creation of graphic images. This library was awarded with special prize by MetaQuotes Software Corp.

In this publication we will consider the examples of working with cIntBMP library. In addition, we will cover the algorithms of creation of fractal sets using the Iterated Function Systems.


1. Affine Transformation of Plane

The affine transformation of plane is a mapping . Generally, the affine 2-D transform can be defined with someΒ  matrix andΒ  , vector. The point with coordinates (x,y) tranforms to some other point using the linear transformation:

The transformation must be non-singular, the .Β  The affine transform changes the size times.

The affine transforms does not change the structure of geometric objects (the lines transformed to lines), the AT allows to describe simple “deformation” of the objects, such as rotation, scaling and translation.

Example of affine plane transforms:

1) Rotation of plane on angle:

2) “Scaling” of a plane with and coefficients (X and Y axes):

3) Translation of plane byΒ  vector:

The contraction mappings is the key (see Hutchinson results).

If and have coordinates and and is a metric (for example, Euclid metric: ). The affine transformation called contraction if , where .

Here is an example of affine transformation:

The result is:

2. Similarity Transforms

The fractals constructed the following way: some (simple) geometric object (section, triangle, square) divided into N pieces and M of them used for further “construction” of the the set (if N=M, we will get the integer dimension of the resulting set). Further this process repeated again and again for each of the pieces.

Classic fractals:
Sections:

  • Triadic Koch Curve, N=3, M=4;
  • Cantor Dust, N=3, M=2;

Triangle:

  • Sierpinski Gasket, N=4, M=3;

Squares:

  • Sierpinski Carpet, N=9, M=8;
  • Vichek fractal, N=9, M=5.

and so on.

The fractals have self-similar structure, some of them can defined by several similarity transformations. The structure of affine transform depends on the way of the fractal construction.

As you will see further, it’s very simple, and the only problem we have to solve is to decribe only the first iteration of fractal construction and find the corresponding set of affine tranforms.

Suppose we have some set. According to the fractal creation algorithm we need to reduce it, rotate and “put on a certain place”.Β  The problem is to describe this process using affine transformations, i.e. we need to find the matrix and vector.

It’s easy to prove that it’s enough to take 3 points of the initial set (nontrivial) and tranform them into 3 corresponding points of the “reduced” set. This transformation will lead to 6 linear equations, allowing us to find the a,b,c,d,e,f as solution.

Let’s show it. Suppose triangle transformed to triangle.

By solving the system of linear equations we will able to get the a,b,c,d,e and f coefficients:

Example:Sierpinski Gasket:

The coordinates of the points are:

  • A (0,0)
  • B (0,1)
  • C (1,1)
  • D(0,1/2)
  • E (1/2,1)
  • F(1/2,1/2)

We have 3 tranformations:

  1. ABC -> ADF
  2. ABC -> DBE
  3. ABC -> FEC

The system of linear equations looks as follows:




The solutions are: , ,

We have found the coefficients of three affine transforms. Furher we will use them for creation of self-similar sets.


3. Creating Fractals Using the Iterated Function Systems

The Iterated Function System (IFS) is a set of affine contractions where – is the “weights”. Each of IFS functions is defined by 7 numbers: , whereweights is used when iteration process as a probability of n-th tranformation. It’s better to define their values, proportional to contraction: .

Let’s consider the algorithm of fractal construction using the Iterated Function System (see also Chaos Game).

The first we need is to take some initial point with coordinates . The next, we choose randomly some of the contractions and plot the point . And again, let’s choose randomly one of the contractions and plot . Finally we will have the as a set of points.

The choice of contraction depend on its “probability”. If we repeat the process (for example, to ~30000 points) and plot the resulting set, we will see its structure despite the random process.

Here is an example of Sierpinski Gasket:

Figure  1. The Sierpinski Gasket, generated with IFS coefficients calculated in chapter 2

Figure 1. The Sierpinski Gasket, generated with IFS coefficients calculated in chapter 2

The code:

//+------------------------------------------------------------------+
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β IFS_Sierpinski_Gasket.mq5 |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Copyright 2011, MetaQuotes Software Corp. |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property linkΒ Β Β Β Β Β ""
#property versionΒ Β  "1.00"

//-- include file with cIntBMP class
#include <cIntBMP.mqh>

//-- Sierpinski Gasket IFS coefficients
//-- (a,b,c,d) matricies
double IFS_a[3] = {0.50,Β Β 0.50,Β Β 0.50};
double IFS_b[3] = {0.00,Β Β 0.00,Β Β 0.00};
double IFS_c[3] = {0.00,Β Β 0.00,Β Β 0.00};
double IFS_d[3] = {0.50,Β Β 0.50,Β Β 0.50};
//-- (e,f) vectors
double IFS_e[3] = {0.00,Β Β 0.00,Β Β 0.50};
double IFS_f[3] = {0.00,Β Β 0.50,Β Β 0.50};
//-- "probabilities" of transforms, multiplied by 1000
double IFS_p[3]={333,333,333};

double Probs[3]; // Probs array - used to choose IFS transforms
cIntBMP bmp;Β Β Β Β  // cIntBMP class instance
int scale=350;Β Β // scale coefficient
//+------------------------------------------------------------------+
//| Expert initialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
int OnInit()
Β Β {
//-- Prepare Probs array
Β Β  double m=0;
Β Β  for(int i=0; i<ArraySize(IFS_p); i++)
Β Β Β Β  {
Β Β Β Β Β Β Probs[i]=IFS_p[i]+m;
Β Β Β Β Β Β m=m+IFS_p[i];
Β Β Β Β  }
//-- size of BMP image
Β Β  int XSize=500;
Β Β  int YSize=400;
//-- create bmp image XSizexYSize with clrSeashell background color
Β Β  bmp.Create(XSize,YSize,clrSeashell);
//-- image rectangle
Β Β  bmp.DrawRectangle(0,0,XSize-1,YSize-1,clrBlack);

//-- point coordinates (will be used in construction of set)
Β Β  double x0=0;
Β Β  double y0=0;
Β Β  double x,y;
//-- number of points to calculate (more points - detailed image)
Β Β  int points=1500000;
//-- calculate set
Β Β  for(int i=0; i<points; i++)
Β Β Β Β  {
Β Β Β Β Β Β // choose IFS tranform with probabilities, proportional to defined
Β Β Β Β Β Β double prb=1000*(rand()/32767.0);
Β Β Β Β Β Β for(int k=0; k<ArraySize(IFS_p); k++)
Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β  if(prb<=Probs[k])
Β Β Β Β Β Β Β Β Β Β  {
Β Β Β Β Β Β Β Β Β Β Β Β // affine transformation
Β Β Β Β Β Β Β Β Β Β Β Β x = IFS_a[k] * x0 + IFS_b[k] * y0 + IFS_e[k];
Β Β Β Β Β Β Β Β Β Β Β Β y = IFS_c[k] * x0 + IFS_d[k] * y0 + IFS_f[k];
Β Β Β Β Β Β Β Β Β Β Β Β // update previous coordinates
Β Β Β Β Β Β Β Β Β Β Β Β x0 = x;
Β Β Β Β Β Β Β Β Β Β Β Β y0 = y;
Β Β Β Β Β Β Β Β Β Β Β Β // convert to BMP image coordinates
Β Β Β Β Β Β Β Β Β Β Β Β // (note the Y axis in cIntBMP)
Β Β Β Β Β Β Β Β Β Β Β Β int scX = int (MathRound(XSize/2 + (x-0.5)*scale));
Β Β Β Β Β Β Β Β Β Β Β Β int scY = int (MathRound(YSize/2 + (y-0.5)*scale));
Β Β Β Β Β Β Β Β Β Β Β Β // if the point coordinates inside the image, draw the dot
Β Β Β Β Β Β Β Β Β Β Β Β if(scX>=0 && scX<XSize && scY>=0 && scY<YSize) { bmp.DrawDot(scX,scY,clrDarkBlue); }
Β Β Β Β Β Β Β Β Β Β Β Β break;
Β Β Β Β Β Β Β Β Β Β  }
Β Β Β Β Β Β Β Β }
Β Β Β Β  }
//-- save image to file
Β Β  bmp.Save("bmpimg",true);
//-- plot image on the chart
Β Β  bmp.Show(0,0,"bmpimg","IFS");
//---
Β Β  return(0);
Β Β }
//+------------------------------------------------------------------+
//| Expert deinitialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
Β Β {
//--- delete image from the chart
Β Β  ObjectDelete(0,"IFS");
//--- delete file
Β Β  bmp.Delete("bmpimg",true);
Β Β }
//+------------------------------------------------------------------+

If we set scale to 1350, increase the number of iterations to 15000000, and change the shift the initial point:

int scX = MathRound(XSize/2 + (x-0.75)*scale);
int scY = MathRound(YSize/2 + (y-0.75)*scale);

we will able to see the zoomed region of the set. One can see (Fig. 2), that it has a self-similar structure:

Figure 2. Zoomed region of Sierpinski Gasket

Figure 2. Zoomed region of Sierpinski Gasket

Let’s consider the famous Barnsley’s Fern, proposed by Michael Barnsley. It’s more complex.

Figure 3. Barnsley's Fern

Figure 3. Barnsley’s Fern

The code is similar, but in this case we have 4 IFS contractions with different weights.

//+------------------------------------------------------------------+
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  IFS_fern.mq5 |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Copyright 2011, MetaQuotes Software Corp. |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property linkΒ Β Β Β Β Β ""
#property versionΒ Β  "1.00"
#include <cIntBMP.mqh>
//-- Barnsley Fern IFS coefficients
//-- (a,b,c,d) matricies
double IFS_a[4] = {0.00,Β Β 0.85,Β Β 0.20,Β Β -0.15};
double IFS_b[4] = {0.00,Β Β 0.04, -0.26,Β Β  0.28};
double IFS_c[4] = {0.00, -0.04,Β Β 0.23,Β Β  0.26};
double IFS_d[4] = {0.16,Β Β 0.85,Β Β 0.22,Β Β  0.24};
//-- (e,f) vectors
double IFS_e[4] = {0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00};
double IFS_f[4] = {0.00,Β Β 1.60,Β Β 1.60,Β Β  0.00};
//-- "probabilities" of transforms, multiplied by 1000
double IFS_p[4] = {10,Β Β Β Β  850,Β Β Β Β 70,Β Β Β Β  70};

double Probs[4];
cIntBMP bmp;
int scale=50;
//+------------------------------------------------------------------+
//| Expert initialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
int OnInit()
Β Β {
Β Β  double m=0;
Β Β  for(int i=0; i<ArraySize(IFS_p); i++)
Β Β Β Β  {
Β Β Β Β Β Β Probs[i]=IFS_p[i]+m;
Β Β Β Β Β Β m=m+IFS_p[i];
Β Β Β Β  }

Β Β  int XSize=600;
Β Β  int YSize=600;

Β Β  bmp.Create(XSize,YSize,clrSeashell);

Β Β  bmp.DrawRectangle(0,0,XSize-1,YSize-1,clrBlack);

Β Β  double x0=0;
Β Β  double y0=0;
Β Β  double x,y;

Β Β  int points=250000;

Β Β  for(int i=0; i<points; i++)
Β Β Β Β  {
Β Β Β Β Β Β double prb=1000*(rand()/32767.0);
Β Β Β Β Β Β for(int k=0; k<ArraySize(IFS_p); k++)
Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β  if(prb<=Probs[k])
Β Β Β Β Β Β Β Β Β Β  {
Β Β Β Β Β Β Β Β Β Β Β Β x = IFS_a[k] * x0 + IFS_b[k] * y0 + IFS_e[k];
Β Β Β Β Β Β Β Β Β Β Β Β y = IFS_c[k] * x0 + IFS_d[k] * y0 + IFS_f[k];
Β Β Β Β Β Β Β Β Β Β Β Β x0 = x;
Β Β Β Β Β Β Β Β Β Β Β Β y0 = y;
Β Β Β Β Β Β Β Β Β Β Β Β int scX = int (MathRound(XSize/2 + (x)*scale));
Β Β Β Β Β Β Β Β Β Β Β Β int scY = int (MathRound(YSize/2 + (y-5)*scale));
Β Β Β Β Β Β Β Β Β Β Β Β if(scX>=0 && scX<XSize && scY>=0 && scY<YSize) { bmp.DrawDot(scX,scY,clrForestGreen); }
Β Β Β Β Β Β Β Β Β Β Β Β break;
Β Β Β Β Β Β Β Β Β Β  }
Β Β Β Β Β Β Β Β }
Β Β Β Β  }
Β Β  bmp.Save("bmpimg",true);
Β Β  bmp.Show(0,0,"bmpimg","IFS");
//---
Β Β  return(0);
Β Β }
//+------------------------------------------------------------------+
//| Expert deinitialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
Β Β {
Β Β  ObjectDelete(0,"IFS");
Β Β  bmp.Delete("bmpimg",true);
Β Β }
//+------------------------------------------------------------------+ 

It’s remarkable that such complex structure can be defined by only 28 numbers.

Alternative:   SHE_kanskigor - EA MetaTrader 5

If we increase the scale to 150, and set iterations to 1250000 we will see the zoomed fragment:

Figure 4. A fragment of Barnsley's Fern

Figure 4. A fragment of Barnsley’s Fern

As you see the algorithm is universal, it allows you to generate different fractal sets.

The next example is Sierpinski Carpet, defined by following IFS coefficients:

//-- Sierpinski Gasket IFS coefficients
double IFS_a[8] = {0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333};
double IFS_b[8] = {0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00, 0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00};
double IFS_c[8] = {0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00, 0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00};
double IFS_d[8] = {0.333, 0.333,Β Β 0.333,Β Β 0.333, 0.333,Β Β 0.333,Β Β 0.333, 0.333};
double IFS_e[8] = {-0.125, -3.375, -3.375,Β Β 3.125, 3.125, -3.375, -0.125, 3.125};
double IFS_f[8] = {6.75, 0.25, 6.75,Β Β 0.25, 6.75, 3.5, 0.25, 3.50};
//-- "probabilities", multiplied by 1000
double IFS_p[8]={125,125,125,125,125,125,125,125};

Figure 5. Sierpinski Carpet

Figure 5. Sierpinski Carpet

In chapter 2 we have considered the algorithm of calculation of coefficients of IFS contractions.

Let’s consider how to create the “fractal words”. In Russian, the “Fractals” word looks like:

Figure 6. "Fractals" word in Russian

Figure 6. “Fractals” word in Russian

To find the IFS coefficients, we need to solve the corresponding linear systems. The solutions are:

//-- IFS coefficients of the "Fractals" word in Russian
double IFS_a[28]=
Β Β {
Β Β  0.00, 0.03,Β Β 0.00, 0.09, 0.00, 0.03, -0.00, 0.07, 0.00, 0.07, 0.03,Β Β 0.03,Β Β 0.03,Β Β 0.00,
Β Β  0.04, 0.04, -0.00, 0.09, 0.03, 0.03,Β Β 0.03, 0.03, 0.03, 0.00, 0.05, -0.00,Β Β 0.05,Β Β 0.00
Β Β };

double IFS_b[28]=
Β Β {
Β Β  -0.11, 0.00, 0.07, 0.00, -0.07, 0.00, -0.11,Β Β 0.00, -0.07,Β Β 0.00, -0.11,Β Β 0.11, 0.00, -0.14,
Β Β  -0.12, 0.12,-0.11, 0.00, -0.11, 0.11,Β Β 0.00, -0.11,Β Β 0.11, -0.11,Β Β 0.00, -0.07, 0.00, -0.07
Β Β };

double IFS_c[28]=
Β Β {
Β Β  0.12,Β Β 0.00,Β Β 0.08,Β Β -0.00,Β Β 0.08,Β Β 0.00,Β Β 0.12,Β Β 0.00,Β Β 0.04,Β Β 0.00,Β Β 0.12,Β Β -0.12, 0.00,Β Β 0.12,
Β Β  0.06,Β Β -0.06,Β Β 0.10,Β Β 0.00,Β Β 0.12,Β Β -0.12,Β Β 0.00,Β Β 0.12,Β Β -0.12,Β Β 0.12, 0.00,Β Β 0.04,Β Β 0.00,Β Β 0.12
Β Β };

double IFS_d[28]=
Β Β {
Β Β  0.00,Β Β 0.05,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.05,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.00,Β Β 0.07,Β Β 0.00,
Β Β  0.00,Β Β 0.00,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.00,Β Β 0.00,Β Β 0.07,Β Β 0.00,Β Β 0.07,Β Β 0.00
Β Β };

double IFS_e[28]=
Β Β {
Β Β  -4.58,Β Β -5.06, -5.16, -4.70, -4.09, -4.35, -3.73, -3.26, -2.76,Β Β -3.26, -2.22, -1.86, -2.04, -0.98,
Β Β  -0.46,Β Β -0.76,Β Β 0.76,Β Β 0.63,Β Β 1.78,Β Β 2.14,Β Β 1.96,Β Β 3.11,Β Β 3.47,Β Β 4.27,Β Β 4.60,Β Β 4.98,Β Β  4.60, 5.24
Β Β };

double IFS_f[28]=
Β Β {
Β Β  1.26,Β Β 0.89,Β Β 1.52,Β Β 2.00,Β Β 1.52,Β Β 0.89,Β Β 1.43,Β Β 1.96,Β Β 1.69,Β Β 1.24,Β Β 1.43,Β Β 1.41,Β Β 1.11,Β Β 1.43,
Β Β  1.79,Β Β 1.05,Β Β 1.32,Β Β 1.96,Β Β 1.43,Β Β 1.41,Β Β 1.11,Β Β 1.43,Β Β 1.41,Β Β 1.43,Β Β 1.42,Β Β 1.16,Β Β 0.71,Β Β 1.43
Β Β };

//-- "probabilities", multiplied by 1000
double IFS_p[28]=
Β Β {
Β Β  35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 
Β Β  35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35,Β Β 35
Β Β };

As a result, we will get the following image:

Figure 7. Self-similar word

Figure 7. Self-similar word

The full source code can be found in ifs_fractals.mq5.

If we zoom the set, we see the self-similar structure:

Figure 8. Zoomed region of the set

Figure 8. Zoomed region of the set

The self-similar sets, based on IFS, can be constructed using the Fractal Designer.

We have covered the topic of creating fractal sets using the Iterated Function Systems. Thanks to the cIntBMP library, the process is very simple. Now it’s time to create a class and add some features to make the images better.


You may notice that correct construction of sets driven by probabilites. The difference in probabilities means that set has irregular structure (see weights of Barnsley Fern IFS). This fact can be used for creation of beautiful images. We need to set the color, proportional to the frequency of the point in some neighbourhood.

It can be done using the virtual screen (just an array), if the pixel color will depend on the previous values. Finally, the virtual screen will be rendered into the bmp using the Palette. The bmp image itself can be drawn as a background picture of the chart.

Here is the code of Expert Advisor, based on CIFS class:

//+------------------------------------------------------------------+
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  IFS_Fern_color.mq5 |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Copyright 2011, MetaQuotes Software Corp. |
//|Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
#include <cIntBMP.mqh>
//-- Barnsley Fern IFS coefficients
double IFS_a[4] = {0.00,Β Β 0.85,Β Β 0.20,Β Β -0.15};
double IFS_b[4] = {0.00,Β Β 0.04, -0.26,Β Β  0.28};
double IFS_c[4] = {0.00, -0.04,Β Β 0.23,Β Β  0.26};
double IFS_d[4] = {0.16,Β Β 0.85,Β Β 0.22,Β Β  0.24};
double IFS_e[4] = {0.00,Β Β 0.00,Β Β 0.00,Β Β  0.00};
double IFS_f[4] = {0.00,Β Β 1.60,Β Β 1.60,Β Β  0.00};
double IFS_p[4] = {10,Β Β Β Β  850,Β Β Β Β 70,Β Β Β Β  70};
//-- Palette
uchar Palette[23*3]=
Β Β {
Β Β  0x00,0x00,0x00,0x02,0x0A,0x06,0x03,0x11,0x0A,0x0B,0x1E,0x0F,0x0C,0x4C,0x2C,0x1C,0x50,0x28,
Β Β  0x2C,0x54,0x24,0x3C,0x58,0x20,0x4C,0x5C,0x1C,0x70,0x98,0x6C,0x38,0xBC,0xB0,0x28,0xCC,0xC8,
Β Β  0x4C,0xB0,0x98,0x5C,0xA4,0x84,0xBC,0x68,0x14,0xA8,0x74,0x28,0x84,0x8C,0x54,0x94,0x80,0x40,
Β Β  0x87,0x87,0x87,0x9F,0x9F,0x9F,0xC7,0xC7,0xC7,0xDF,0xDF,0xDF,0xFC,0xFC,0xFC
Β Β };
//+------------------------------------------------------------------+
//| CIFS classΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
class CIFS
Β Β {
protected:
Β Β  cIntBMPΒ Β Β Β Β Β Β Β Β Β  m_bmp;
Β Β  intΒ Β Β Β Β Β Β Β Β Β Β Β Β Β  m_xsize;
Β Β  intΒ Β Β Β Β Β Β Β Β Β Β Β Β Β  m_ysize;
Β Β  ucharΒ Β Β Β Β Β Β Β Β Β Β Β  m_virtual_screen[];
Β Β  doubleΒ Β Β Β Β Β Β Β Β Β Β Β m_scale;
Β Β  doubleΒ Β Β Β Β Β Β Β Β Β Β Β m_probs[8];

public:
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β ~CIFS()Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β { m_bmp.Delete("bmpimg",true); };
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Create(int x_size,int y_size,uchar col);
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Render(double scale,bool back);
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β ShowBMP(bool back);
protected:
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β VS_Prepare(int x_size,int y_size,uchar col);
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β VS_Fill(uchar col);
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β VS_PutPixel(int px,int py,uchar col);
Β Β  ucharΒ Β Β Β Β Β Β Β Β Β Β Β  VS_GetPixel(int px,int py);
Β Β  intΒ Β Β Β Β Β Β Β Β Β Β Β Β Β  GetPalColor(uchar index);
Β Β  intΒ Β Β Β Β Β Β Β Β Β Β Β Β Β  RGB256(int r,int g,int b) const {return(r+256*g+65536*b);Β Β Β Β Β Β }
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β PrepareProbabilities();
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β RenderIFSToVirtualScreen();
Β Β  voidΒ Β Β Β Β Β Β Β Β Β Β Β Β Β VirtualScreenToBMP();
Β Β };
//+------------------------------------------------------------------+
//| Create methodΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |
//+------------------------------------------------------------------+
void CIFS::Create(int x_size,int y_size,uchar col)
Β Β {
Β Β  m_bmp.Create(x_size,y_size,col);
Β Β  VS_Prepare(x_size,y_size,col);
Β Β  PrepareProbabilities();
Β Β }
//+------------------------------------------------------------------+
//| Prepares virtual screenΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |
//+------------------------------------------------------------------+
void CIFS::VS_Prepare(int x_size,int y_size,uchar col)
Β Β {
Β Β  m_xsize=x_size;
Β Β  m_ysize=y_size;
Β Β  ArrayResize(m_virtual_screen,m_xsize*m_ysize);
Β Β  VS_Fill(col);
Β Β }
//+------------------------------------------------------------------+
//| Fills the virtual screen with specified colorΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |
//+------------------------------------------------------------------+
void CIFS::VS_Fill(uchar col)
Β Β {
Β Β  for(int i=0; i<m_xsize*m_ysize; i++) {m_virtual_screen[i]=col;}
Β Β }
//+------------------------------------------------------------------+
//| Returns the color from paletteΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
int CIFS::GetPalColor(uchar index)
Β Β {
Β Β  int ind=index;
Β Β  if(ind<=0) {ind=0;}
Β Β  if(ind>22) {ind=22;}
Β Β  uchar r=Palette[3*(ind)];
Β Β  uchar g=Palette[3*(ind)+1];
Β Β  uchar b=Palette[3*(ind)+2];
Β Β  return(RGB256(r,g,b));
Β Β }
//+------------------------------------------------------------------+
//| Draws a pixel on the virtual screenΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |
//+------------------------------------------------------------------+
void CIFS::VS_PutPixel(int px,int py,uchar col)
Β Β {
Β Β  if (px<0) return;
Β Β  if (py<0) return;
Β Β  if (px>m_xsize) return;
Β Β  if (py>m_ysize) return;
Β Β Β Β int pos=m_xsize*py+px;
Β Β  if(pos>=ArraySize(m_virtual_screen)) return;
Β Β  m_virtual_screen[pos]=col;
Β Β }
//+------------------------------------------------------------------+
//| Gets the pixel "color" from the virtual screenΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
uchar CIFS::VS_GetPixel(int px,int py)
Β Β {
Β Β  if (px<0) return(0);
Β Β  if (py<0) return(0);
Β Β  if (px>m_xsize) return(0);
Β Β  if (py>m_ysize) return(0);
Β Β Β Β int pos=m_xsize*py+px;
Β Β  if(pos>=ArraySize(m_virtual_screen)) return(0);
Β Β  return(m_virtual_screen[pos]);
Β Β }
//+------------------------------------------------------------------+
//| Prepare the cumulative probabilities arrayΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void CIFS::PrepareProbabilities()
Β Β {
Β Β  double m=0;
Β Β  for(int i=0; i<ArraySize(IFS_p); i++)
Β Β Β Β  {
Β Β Β Β Β Β m_probs[i]=IFS_p[i]+m;
Β Β Β Β Β Β m=m+IFS_p[i];
Β Β Β Β  }
Β Β }
//+------------------------------------------------------------------+
//| Renders the IFS set to the virtual screenΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |
//+------------------------------------------------------------------+
void CIFS::RenderIFSToVirtualScreen()
Β Β {
Β Β  double x=0,y=0;
Β Β  double x0=0;
Β Β  double y0=0;
Β Β  uint iterations= uint (MathRound(100000+100*MathPow(m_scale,2)));

Β Β  for(uint i=0; i<iterations; i++)
Β Β Β Β  {
Β Β Β Β Β Β double prb=1000*(rand()/32767.0);

Β Β Β Β Β Β for(int k=0; k<ArraySize(IFS_p); k++)
Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β  if(prb<=m_probs[k])
Β Β Β Β Β Β Β Β Β Β  {
Β Β Β Β Β Β Β Β Β Β Β Β x = IFS_a[k] * x0 + IFS_b[k] * y0 + IFS_e[k];
Β Β Β Β Β Β Β Β Β Β Β Β y = IFS_c[k] * x0 + IFS_d[k] * y0 + IFS_f[k];

Β Β Β Β Β Β Β Β Β Β Β Β int scX = int (MathRound(m_xsize/2 + (x-0)*m_scale));
Β Β Β Β Β Β Β Β Β Β Β Β int scY = int (MathRound(m_ysize/2 + (y-5)*m_scale));

Β Β Β Β Β Β Β Β Β Β Β Β if(scX>=0 && scX<m_xsize && scY>=0 && scY<m_ysize)
Β Β Β Β Β Β Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β Β Β Β Β Β Β  uchar c=VS_GetPixel(scX,scY);
Β Β Β Β Β Β Β Β Β Β Β Β Β Β  if(c<255) c=c+1;
Β Β Β Β Β Β Β Β Β Β Β Β Β Β  VS_PutPixel(scX,scY,c);
Β Β Β Β Β Β Β Β Β Β Β Β Β Β }
Β Β Β Β Β Β Β Β Β Β Β Β break;
Β Β Β Β Β Β Β Β Β Β  }
Β Β Β Β Β Β Β Β  x0 = x;
Β Β Β Β Β Β Β Β  y0 = y;
Β Β Β Β Β Β Β Β }
Β Β Β Β  }
Β Β }
//+------------------------------------------------------------------+
//| Copies virtual screen to BMPΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void CIFS::VirtualScreenToBMP()
Β Β {
Β Β  for(int i=0; i<m_xsize; i++)
Β Β Β Β  {
Β Β Β Β Β Β for(int j=0; j<m_ysize; j++)
Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β  uchar colind=VS_GetPixel(i,j);
Β Β Β Β Β Β Β Β  int xcol=GetPalColor(colind);
Β Β Β Β Β Β Β Β  if(colind==0) xcol=0x00;
Β Β Β Β Β Β Β Β  //if(colind==0) xcol=0xFFFFFF;
Β Β Β Β Β Β Β Β  m_bmp.DrawDot(i,j,xcol);
Β Β Β Β Β Β Β Β }
Β Β Β Β  }
Β Β }
//+------------------------------------------------------------------+
//| Shows BMP image on the chartΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void CIFS::ShowBMP(bool back)
Β Β {
Β Β  m_bmp.Save("bmpimg",true);
Β Β  m_bmp.Show(0,0,"bmpimg","Fern");
Β Β  ObjectSetInteger(0,"Fern",OBJPROP_BACK,back);
Β Β }
//+------------------------------------------------------------------+
//| Render methodΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β |Β Β Β Β  
//+------------------------------------------------------------------+
void CIFS::Render(double scale,bool back)
Β Β {
Β Β  m_scale=scale;
Β Β  VS_Fill(0);
Β Β  RenderIFSToVirtualScreen();
Β Β  VirtualScreenToBMP();
Β Β  ShowBMP(back);
Β Β }

static int gridmode;
CIFS fern;
int currentscale=50;
//+------------------------------------------------------------------+
//| Expert initialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void OnInit()
Β Β {
//-- get grid mode
Β Β  gridmode= int (ChartGetInteger(0,CHART_SHOW_GRID,0));
//-- disable grid
Β Β  ChartSetInteger(0,CHART_SHOW_GRID,0);
//-- create bmp
Β Β  fern.Create(800,800,0x00);
//-- show as backround image
Β Β  fern.Render(currentscale,true);
Β Β }
//+------------------------------------------------------------------+
//| Expert deinitialization functionΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void OnDeinit(const int r)
Β Β {
//-- restore grid mode
Β Β  ChartSetInteger(0,CHART_SHOW_GRID,gridmode); 
//-- delete Fern object
Β Β  ObjectDelete(0,"Fern");
 }
//+------------------------------------------------------------------+
//| Expert OnChart event handlerΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,Β Β Β Β Β Β Β   Β  // Event identifierΒ Β 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  const long& lparam,Β Β  // Event parameter of long type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  const double& dparam, // Event parameter of double type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  const string& sparamΒ Β // Event parameter of string type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  )
Β Β {
//--- click on the graphic object
Β Β  if(id==CHARTEVENT_OBJECT_CLICK)
Β Β Β Β  {
Β Β Β Β Β Β Print("Click event on graphic object with name '"+sparam+"'");
Β Β Β Β Β Β if(sparam=="Fern")
Β Β Β Β Β Β Β Β {
Β Β Β Β Β Β Β Β  // increase scale coefficient (zoom)
Β Β Β Β Β Β Β Β  currentscale=int (currentscale*1.1);
Β Β Β Β Β Β Β Β  fern.Render(currentscale,true);
Β Β Β Β Β Β Β Β }
Β Β Β Β  }
Β Β }
//+------------------------------------------------------------------+

The result is:

Alternative:   ColorZerolagJJRSXTrend_x10 - indicator MetaTrader 5

Figure 9. Barnsley's fern image, created with CIFS class

Figure 9. Barnsley’s fern image, created with CIFS class


Figure 10. The zoomed region of Barnsley's Fern

Figure 10. The zoomed region of Barnsley’s Fern


Figure 11. The zoomed region of Barnsley's Fern

Figure 11. The zoomed region of Barnsley’s Fern


Figure 12. The zoomed region of Barnsley's Fern

Figure 12. The zoomed region of Barnsley’s Fern

Do It Yourself

1. There is a lot of IFS fractals in Fractint, for example:

// Binary
double IFS_a[3] = { 0.5,Β Β 0.5,Β Β 0.0};
double IFS_b[3] = { 0.0,Β Β 0.0, -0.5};
double IFS_c[4] = { 0.0,Β Β 0.0,Β Β 0.5};
double IFS_d[4] = { 0.5,Β Β 0.5,Β Β 0.5};
double IFS_e[4] = {-2.563477,Β Β 2.436544, 4.873085};
double IFS_f[4] = {-0.000000, -0.000003, 7.563492};
double IFS_p[4] = {333, 333, 333};

// Coral
double IFS_a[3] = { 0.307692,Β Β 0.307692,Β Β 0.000000};
double IFS_b[3] = {-0.531469, -0.076923,Β Β 0.54545};
double IFS_c[3] = {-0.461538,Β Β 0.153846,Β Β 0.692308};
double IFS_d[3] = {-0.293706, -0.447552, -0.195804};
double IFS_e[3] = {5.4019537, -1.295248, -4.893637};
double IFS_f[3] = { 8.655175,Β  4.152990,Β Β 7.269794};
double IFS_p[3] = {400, 150, 450};

// Crystal
double IFS_a[2] = { 0.696970,  0.090909};
double IFS_b[2] = {-0.481061, -0.443182};
double IFS_c[2] = {-0.393939,Β Β 0.515152};
double IFS_d[2] = {-0.662879, -0.094697};
double IFS_e[2] = { 2.147003,Β Β 4.286558};
double IFS_f[2] = {10.310288,Β Β 2.925762};
double IFS_p[2] = {750, 250};

// Dragon
double IFS_a[2] = { 0.824074,Β Β 0.088272};
double IFS_b[2] = { 0.281482,Β Β 0.520988};
double IFS_c[2] = {-0.212346, -0.463889};
double IFS_d[2] = { 0.864198, -0.377778};
double IFS_e[2] = {-1.882290,Β Β 0.785360};
double IFS_f[2] = {-0.110607,Β Β 8.095795};
double IFS_p[2] = {780, 220};

// Floor
double IFS_a[3] = { 0,Β Β 0.52,Β Β 0};
double IFS_b[3] = {-0.5, Β  0,  0.5};
double IFS_c[3] = { 0.5,Β  Β 0, -0.5};
double IFS_d[3] = { 0,Β Β  0.5,Β Β 0};
double IFS_e[3] = {-1.732366, -0.027891,Β Β 1.620804};
double IFS_f[3] = { 3.366182,  5.014877,Β Β 3.310401};
double IFS_p[3] = {333, 333, 333};

// Koch3
double IFS_a[5] = {0.307692, 0.192308,Β Β 0.192308,  0.307692,  0.384615};
double IFS_b[5] = {Β Β Β Β Β  0,-0.205882,  0.205882,         0,        0};
double IFS_c[5] = {Β Β Β Β Β  0, 0.653846, -0.653846,         0,         0};
double IFS_d[5] = {0.294118, 0.088235,  0.088235,  0.294118, -0.294118};
double IFS_e[5] = {4.119164,-0.688840,Β Β 0.688840, -4.136530, -0.007718};
double IFS_f[5] = {1.604278, 5.978916,Β Β 5.962514,  1.604278,  2.941176};
double IFS_p[5] = {151, 254, 254, 151, 190};

//Spiral
double IFS_a[3] = { 0.787879, -0.121212,Β Β 0.181818};
double IFS_b[3] = {-0.424242,Β Β 0.257576, -0.136364};
double IFS_c[3] = { 0.242424,Β Β 0.151515,Β Β 0.090909};
double IFS_d[3] = { 0.859848,Β Β 0.053030,Β Β 0.181818};
double IFS_e[3] = { 1.758647,Β Β -6.721654,Β Β 6.086107};
double IFS_f[3] = { 1.408065,Β  Β 1.377236,Β Β 1.568035};
double IFS_p[3] = {896, 52, 52};

//Swirl5
double IFS_a[2] = {  0.74545, -0.424242};
double IFS_b[2] = {-0.459091, -0.065152};
double IFS_c[2] = { 0.406061, -0.175758};
double IFS_d[2] = { 0.887121, -0.218182};
double IFS_e[2] = { 1.460279,Β Β 3.809567};
double IFS_f[2] = { 0.691072,Β Β 6.741476};
double IFS_p[2] = {920, 80};

//Zigzag2
double IFS_a[2] = {-0.632407, -0.036111};
double IFS_b[2] = {-0.614815, 0.444444};
double IFS_c[2] = {-0.545370, 0.210185};
double IFS_d[2] = { 0.659259, 0.037037};
double IFS_e[2] = { 3.840822, 2.071081};
double IFS_f[2] = { 1.282321, 8.330552};
double IFS_p[2] = {888, 112};

Plot these sets. How to find the initial similarity transforms using the IFS coefficients?

2. Create your own fractals sets and calculate their coefficients (chapter 2).

3. Try to play with palette colors (uchar Palette array), extend the palette and add gradient colors.

4. What about the fractal (Hausdorf-Bezikovitch) dimension of Barnsley’s Fern? Is there a formula for calculation of fractal dimension using the IFS coefficients*.

5. Add zoom of a certain region, using the information about the mouse click coordinates in OnChartEvent:

void OnChartEvent(const int id,Β Β Β Β Β Β Β Β  // Event identifierΒ Β 
Β Β Β Β Β Β Β Β Β Β Β Β Β  Β  const long& lparam,Β Β  // Event parameter of long type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  const double& dparam, // Event parameter of double type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  const string& sparamΒ Β // Event parameter of string type
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  )
Β Β {
//--- left button click
Β Β  if(id==CHARTEVENT_CLICK)
Β Β Β Β  {
Β Β Β Β Β Β Print("Coordinates: x=",lparam,"Β Β y=",dparam);
Β Β Β Β  }
Β Β }

Conclusion

We have considered the algorithm of creation of self-similar sets using the Iterated Function System.

The use of cIntBMP library greatly simplifies the work with graphic images. Besides the DrawDot(x,y,color) method we have used, the cIntBMP class contains many other useful methods. But it’s another story.



/ru/code/328

πŸ“ˆ ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks