Logiciel libre de géométrie, d'analyse et de simulation multiplateforme par Yves Biton

Accueil Tutoriels l’API de MathGraph32

Programming a figure in Python : The Hilbert curve

modification vendredi 22 avril 2024.

Toutes les versions de cet article : [English] [français]



Since 7.9.1 version, MathGraph32 allows to create graphical objects in Python language.

Here we will generate a fractal curve : the Hilbert curve.

If you change the Python code here under, click on button Execute under the edition windows.

The created figure is dynamic : you can capture points A, B and C when the code has been executed.
Click on one of the yellow buttons to launch the construction at a given depth.

Yoy will find at the bottom of this article explanations about the used method and the API functions used.


How the figure is constructed

The basic construction is displayed here under :

The three basic points are A, B et C.

We start with the creation of midpoints I and J, segments [AB] and [BC] then point D, image of A through the dilation of center C et ration -1/4.
Then we create with a sequence of translations points D, E, F, G, H, K, L, M, N, O, P, Q, R, S, T, U and we generate the broken line for depth 0.

For depth 1, we iterate four times the preceeding construction :
- Replacing A, B and C by D, E and FDoing so we get the figure here under (the green segments connect the four added broken lines).


The theorical Hilbert curve is obtained by iterating this process to the infinite. It is a continuoux curve that fills entirely a square (here a parallelogram).

In the figure aboven we limit the depth of recursion to a value of 5. Going above this limit outpass the screen definition.

Explanations on the API functions used in this code :

Firts we create three free points with the following lines :

A = addFreePoint({'x':width/4 + 20, 'y':3*height/4 - 20, 'name':'A', 'color':'red', 'absCoord': True})
B = addFreePoint({'x':3*width/4 - 20, 'y':3*height/4 - 20, 'name':'B', 'color':'red', 'absCoord': True})
C = addFreePoint({'x':3*width/4 - 20, 'y':height/4 + 20, 'name':'C', 'color':'red', 'absCoord': True})

Here we use the object syntax to create these free points to pass parameter absCoord to true which implies that the starting coordinates for the free points are in SVG coordinates (x-coordinates increasing from left to right and y-coordinates increasing from top to bottom)

The code of the recursive function hilbert(A, B, C, prof, tabPoints) is rather easy to understand in regard to the explanations given before.

The function adds to list points (empty before the calls) the points created at the last level of recursion.
This list is then used to create the final broken line..

Functions hilbertNiv0, hilbertNiv1, hilbertNiv2, hilbertNiv3, hilbertNiv4 and hilbertNiv5 create the final broken line at final recursion depth of 0, 1, 2, 3, 4 et 5.

The following lines create buttons that, when clicked upon, will launch the above functions :

btn0 = addActionButton('Hilbert prof = 0', hilbertNiv0, 10, 10, 'btn0')
btn1 = addActionButton('Hilbert prof = 1', hilbertNiv1, 10, 40, 'btn1')
btn2 = addActionButton('Hilbert prof = 2', hilbertNiv2, 10, 70, 'btn2')
btn3 = addActionButton('Hilbert prof = 3', hilbertNiv3, 10, 100, 'btn3')
btn4 = addActionButton('Hilbert prof = 4', hilbertNiv4, 10, 130, 'btn4')
btn5 = addActionButton('Hilbert prof = 5', hilbertNiv5, 10, 160, 'btn5')

The two followig lines :

W = addFreePoint(0, 0, 'W')
setHidden(W)

create after these buttons an hidden point W. The only use of W is to help destroy all the objects created after it W in functions hilbertNiv0 à hilbertNiv5.

Now let’s look at the code of function hilbertNiv5 :

def hilbertNiv5():
   deleteAfter('W')
   points = []
   hilbert(A, B, C, 5, points)
   addBrokenLine(points, 'blue')
   displayButtonsOnTop()

First this function destroys all the objects created after point W (along with theig graphical implementation if they are graphica). These objects can be objects created after clicking on one of the yellow buttons..
Then list points is initialized with an empty list.
Then function hilbert is launched on points A, B and C with a max depth of 5.
Then the broken liken line is created using the list points generated by function hilbert.
Then the function displayButtonsOnTop is called.
This function reclasses the graphic representation of the yellow buttons in order to make these not to be hidden by the broken line created after using the hilbert function.

Here is the code of this function :

def displayButtonsOnTop():
   displayOnTop('btn0')
   displayOnTop('btn1')
   displayOnTop('btn2')
   displayOnTop('btn3')
   displayOnTop('btn4')
   displayOnTop('btn5')

For instance, the first button has been created with the following code : btn0 = addActionButton(’Hilbert prof = 0’, hilbertNiv0, 10, 10, ’btn0’)
The last parameter ’btn0’ is a MathGraph32 tag that is applied on this button.
This tag is passed as parameter in line : displayOnTop(’btn0’)
Why not passing as argument the object btn0 ? The button is necessarily created after the function hilbertNiv0, function using the same function displayButtonsOnTop.
This objet cannot be used due to Python rules (no use of an object created afterward) , so we use the tag the button has been assigned at, string ’btn0’